Merge branch 'master' of https://github.com/supertuxkart/stk-code
This commit is contained in:
commit
ce28d46d14
@ -333,11 +333,10 @@ bool MusicOggStream::streamIntoBuffer(ALuint buffer)
|
||||
|
||||
int size = 0;
|
||||
int portion;
|
||||
int result;
|
||||
|
||||
while(size < m_buffer_size)
|
||||
{
|
||||
result = ov_read(&m_oggStream, pcm + size, m_buffer_size - size,
|
||||
int result = ov_read(&m_oggStream, pcm + size, m_buffer_size - size,
|
||||
isBigEndian, 2, 1, &portion);
|
||||
|
||||
if(result > 0)
|
||||
|
@ -516,7 +516,6 @@ const irr::core::stringw
|
||||
if (track == NULL) return irr::core::stringw( L"????" );
|
||||
|
||||
return _("New track '%s' now available", track->getName());
|
||||
break;
|
||||
}
|
||||
case UNLOCK_MODE:
|
||||
{
|
||||
|
@ -81,7 +81,7 @@ void CameraNormal::smoothMoveCamera(float dt)
|
||||
const KartProperties *kp = m_kart->getKartProperties();
|
||||
float max_increase_with_zipper = kp->getZipperMaxSpeedIncrease();
|
||||
float max_speed_without_zipper = kp->getEngineMaxSpeed();
|
||||
float current_speed = m_kart->getSpeed();
|
||||
float current_speed = m_kart->getSmoothedSpeed();
|
||||
|
||||
const Skidding *ks = m_kart->getSkidding();
|
||||
float skid_factor = ks->getVisualSkidRotation();
|
||||
@ -106,10 +106,10 @@ void CameraNormal::smoothMoveCamera(float dt)
|
||||
core::vector3df wanted_position = m_kart_camera_position_with_offset.toIrrVector();
|
||||
|
||||
float f = 5.0f;
|
||||
if ((m_kart->getSpeed() > 5 ) || (m_kart->getSpeed() < 0 ))
|
||||
if ((current_speed > 5 ) || (current_speed < 0 ))
|
||||
{
|
||||
f = m_kart->getSpeed()>0 ? m_kart->getSpeed()/3 + 1.0f
|
||||
: -1.5f * m_kart->getSpeed() + 2.0f;
|
||||
f = current_speed >0 ? current_speed/3 + 1.0f
|
||||
: -1.5f * current_speed + 2.0f;
|
||||
}
|
||||
current_position += (wanted_position - current_position) * (dt *f);
|
||||
|
||||
|
@ -219,7 +219,7 @@ void IrrDriver::computeMatrixesAndCameras(scene::ICameraSceneNode *const camnode
|
||||
float w = width * UserConfigParams::m_scale_rtts_factor;
|
||||
float h = height * UserConfigParams::m_scale_rtts_factor;
|
||||
m_current_screen_size = core::vector2df(w, h);
|
||||
m_shadow_matrices->computeMatrixesAndCameras(camnode, w, h);
|
||||
m_shadow_matrices->computeMatrixesAndCameras(camnode, int(w), int(h));
|
||||
} // computeMatrixesAndCameras
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -1600,7 +1600,7 @@ std::string IrrDriver::getSmallerTexture(const std::string& filename)
|
||||
{
|
||||
core::dimension2d<u32> dim = img->getDimension();
|
||||
core::dimension2d<u32> new_dim; // Dimension of the cached texture
|
||||
const int scale_factor = 2;
|
||||
const unsigned scale_factor = 2;
|
||||
// Resize the texture only if it can be done properly
|
||||
if (dim.Width < scale_factor || dim.Height < scale_factor)
|
||||
new_dim = dim;
|
||||
|
@ -1319,9 +1319,9 @@ void multidraw2ndPass(const std::vector<uint64_t> &Handles, Args... args)
|
||||
T::InstancedSecondPassShader::getInstance()->use();
|
||||
glBindVertexArray(VAOManager::getInstance()->getInstanceVAO(T::VertexType,
|
||||
T::Instance));
|
||||
uint64_t nulltex[10] = {};
|
||||
if (SolidPassCmd::getInstance()->Size[T::MaterialType])
|
||||
{
|
||||
uint64_t nulltex[10] = {};
|
||||
HandleExpander<typename T::InstancedSecondPassShader>::template
|
||||
Expand(nulltex, T::SecondPassTextures, Handles[0], Handles[1],
|
||||
Handles[2]);
|
||||
@ -1410,9 +1410,9 @@ void IrrDriver::renderSolidSecondPass()
|
||||
GrassMat::InstancedSecondPassShader::getInstance()->use();
|
||||
glBindVertexArray(VAOManager::getInstance()->getInstanceVAO(GrassMat::VertexType,
|
||||
GrassMat::Instance));
|
||||
uint64_t nulltex[10] = {};
|
||||
if (SolidPassCmd::getInstance()->Size[GrassMat::MaterialType])
|
||||
{
|
||||
uint64_t nulltex[10] = {};
|
||||
HandleExpander<GrassMat::InstancedSecondPassShader>
|
||||
::Expand(nulltex, GrassMat::SecondPassTextures, DiffuseHandle,
|
||||
SpecularHandle, SSAOHandle, DepthHandle);
|
||||
|
@ -314,20 +314,6 @@ void ShadowMatrices::computeMatrixesAndCameras(scene::ICameraSceneNode *const ca
|
||||
|
||||
const float oldfar = camnode->getFarValue();
|
||||
const float oldnear = camnode->getNearValue();
|
||||
float FarValues[] =
|
||||
{
|
||||
ShadowMatrices::m_shadow_split[1],
|
||||
ShadowMatrices::m_shadow_split[2],
|
||||
ShadowMatrices::m_shadow_split[3],
|
||||
ShadowMatrices::m_shadow_split[4],
|
||||
};
|
||||
float NearValues[] =
|
||||
{
|
||||
ShadowMatrices::m_shadow_split[0],
|
||||
ShadowMatrices::m_shadow_split[1],
|
||||
ShadowMatrices::m_shadow_split[2],
|
||||
ShadowMatrices::m_shadow_split[3]
|
||||
};
|
||||
|
||||
float tmp[16 * 9 + 2];
|
||||
memcpy(tmp, irr_driver->getViewMatrix().pointer(), 16 * sizeof(float));
|
||||
@ -359,6 +345,21 @@ void ShadowMatrices::computeMatrixesAndCameras(scene::ICameraSceneNode *const ca
|
||||
core::aabbox3df trackbox(vmin.toIrrVector(), vmax.toIrrVector() -
|
||||
core::vector3df(0, 30, 0));
|
||||
|
||||
float FarValues[] =
|
||||
{
|
||||
ShadowMatrices::m_shadow_split[1],
|
||||
ShadowMatrices::m_shadow_split[2],
|
||||
ShadowMatrices::m_shadow_split[3],
|
||||
ShadowMatrices::m_shadow_split[4],
|
||||
};
|
||||
float NearValues[] =
|
||||
{
|
||||
ShadowMatrices::m_shadow_split[0],
|
||||
ShadowMatrices::m_shadow_split[1],
|
||||
ShadowMatrices::m_shadow_split[2],
|
||||
ShadowMatrices::m_shadow_split[3]
|
||||
};
|
||||
|
||||
// Shadow Matrixes and cameras
|
||||
for (unsigned i = 0; i < 4; i++)
|
||||
{
|
||||
|
@ -723,7 +723,7 @@ PROFILER_POP_CPU_MARKER();
|
||||
ListInstancedMatDetails::getInstance()->clear();
|
||||
ListInstancedMatUnlit::getInstance()->clear();
|
||||
|
||||
size_t SolidPoly = 0, ShadowPoly = 0, MiscPoly = 0;
|
||||
size_t SolidPoly = 0, ShadowPoly = 0;
|
||||
|
||||
PROFILER_PUSH_CPU_MARKER("- Draw Command upload", 0xFF, 0x0, 0xFF);
|
||||
|
||||
@ -868,6 +868,8 @@ PROFILER_POP_CPU_MARKER();
|
||||
RSMCmdBuffer = (DrawElementsIndirectCommand*)glMapBufferRange(GL_DRAW_INDIRECT_BUFFER, 0, 10000 * sizeof(DrawElementsIndirectCommand), GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
|
||||
}
|
||||
|
||||
size_t MiscPoly = 0;
|
||||
|
||||
// Default Material
|
||||
RSMPassCmd::getInstance()->Offset[Material::SHADERTYPE_SOLID] = current_cmd;
|
||||
FillInstances(MeshForRSM[Material::SHADERTYPE_SOLID], ListInstancedMatDefault::getInstance()->RSM, RSMInstanceBuffer, RSMCmdBuffer, offset, current_cmd, MiscPoly);
|
||||
|
@ -387,7 +387,7 @@ const bool NAVIGATION_DEBUG = false;
|
||||
*/
|
||||
void EventHandler::navigate(const int playerID, Input::InputType type, const bool pressedDown, const bool reverse)
|
||||
{
|
||||
IGUIElement *el = NULL, *closest = NULL;
|
||||
IGUIElement *el = NULL;
|
||||
|
||||
if (type == Input::IT_STICKBUTTON && !pressedDown)
|
||||
return;
|
||||
@ -450,7 +450,7 @@ void EventHandler::navigate(const int playerID, Input::InputType type, const boo
|
||||
// Down: if the current widget is e.g. 5, search for widget 6, 7, 8, 9, ..., 15 (up to 10 IDs may be missing)
|
||||
for (int n = 1; n < 10 && !found; n++)
|
||||
{
|
||||
closest = GUIEngine::getGUIEnv()->getRootGUIElement()->getElementFromId(el->getTabOrder() + (reverse ? -n : n), true);
|
||||
IGUIElement *closest = GUIEngine::getGUIEnv()->getRootGUIElement()->getElementFromId(el->getTabOrder() + (reverse ? -n : n), true);
|
||||
|
||||
if (closest != NULL && Widget::isFocusableId(closest->getID()))
|
||||
{
|
||||
|
@ -927,7 +927,6 @@ void Skin::drawRibbonChild(const core::recti &rect, Widget* widget,
|
||||
//if (widget->m_deactivated) return;
|
||||
|
||||
bool mark_selected = widget->isSelected(PLAYER_ID_GAME_MASTER);
|
||||
bool always_show_selection = false;
|
||||
|
||||
IGUIElement* focusedElem = NULL;
|
||||
if (GUIEngine::getFocusForPlayer(PLAYER_ID_GAME_MASTER) != NULL)
|
||||
@ -1007,6 +1006,7 @@ void Skin::drawRibbonChild(const core::recti &rect, Widget* widget,
|
||||
|
||||
/* in combo ribbons, always show selection */
|
||||
RibbonWidget* parentRibbonWidget = NULL;
|
||||
bool always_show_selection = false;
|
||||
|
||||
if (widget->m_event_handler != NULL &&
|
||||
widget->m_event_handler->m_type == WTYPE_RIBBON)
|
||||
|
@ -1321,11 +1321,10 @@ void CGUIEditBox::breakText()
|
||||
s32 size = Text.size();
|
||||
s32 length = 0;
|
||||
s32 elWidth = RelativeRect.getWidth() - 6;
|
||||
wchar_t c;
|
||||
|
||||
for (s32 i=0; i<size; ++i)
|
||||
{
|
||||
c = Text[i];
|
||||
wchar_t c = Text[i];
|
||||
bool lineBreak = false;
|
||||
|
||||
if (c == L'\r') // Mac or Windows breaks
|
||||
|
@ -210,7 +210,6 @@ void DynamicRibbonWidget::add()
|
||||
// const int count = m_items.size();
|
||||
|
||||
m_row_amount = -1;
|
||||
float max_score_so_far = -1;
|
||||
|
||||
if (m_h - m_label_height < 0)
|
||||
{
|
||||
@ -219,6 +218,7 @@ void DynamicRibbonWidget::add()
|
||||
}
|
||||
else
|
||||
{
|
||||
float max_score_so_far = -1;
|
||||
for (int row_count = 1; row_count < 10; row_count++)
|
||||
{
|
||||
int visible_items;
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "modes/demo_world.hpp"
|
||||
#include "modes/profile_world.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "network/rewind_manager.hpp"
|
||||
#include "physics/physics.hpp"
|
||||
#include "race/history.hpp"
|
||||
#include "replay/replay_recorder.hpp"
|
||||
@ -100,6 +101,8 @@ InputManager::~InputManager()
|
||||
void InputManager::handleStaticAction(int key, int value)
|
||||
{
|
||||
static bool control_is_pressed = false;
|
||||
static bool shift_is_pressed = false;
|
||||
|
||||
World *world = World::getWorld();
|
||||
|
||||
// When no players... a cutscene
|
||||
@ -149,6 +152,10 @@ void InputManager::handleStaticAction(int key, int value)
|
||||
case KEY_LWIN:
|
||||
control_is_pressed = value!=0;
|
||||
break;
|
||||
case KEY_LSHIFT:
|
||||
case KEY_RSHIFT:
|
||||
case KEY_SHIFT:
|
||||
shift_is_pressed = value!=0; break;
|
||||
|
||||
// Flying up and down
|
||||
case KEY_KEY_I:
|
||||
@ -267,9 +274,22 @@ void InputManager::handleStaticAction(int key, int value)
|
||||
if (value ==0 )
|
||||
irr_driver->requestScreenshot();
|
||||
break;
|
||||
case KEY_F11:
|
||||
if(value && shift_is_pressed && world && RewindManager::isEnabled())
|
||||
{
|
||||
printf("Enter rewind to time:");
|
||||
char s[256];
|
||||
fgets(s, 256, stdin);
|
||||
float t;
|
||||
StringUtils::fromString(s,t);
|
||||
RewindManager::get()->rewindTo(t);
|
||||
Log::info("Rewind", "Rewinding from %f to %f",
|
||||
world->getTime(), t);
|
||||
}
|
||||
break;
|
||||
|
||||
/*
|
||||
case KEY_F1:
|
||||
if (UserConfigParams::m_artist_debug_mode && world)
|
||||
else if (UserConfigParams::m_artist_debug_mode && world)
|
||||
{
|
||||
AbstractKart* kart = world->getLocalPlayerKart(0);
|
||||
|
||||
|
@ -143,7 +143,6 @@ void WiimoteManager::launchDetection(int timeout)
|
||||
|
||||
//To prevent segmentation fault, have to delete NULLs
|
||||
number_deletables = 0;
|
||||
number_deletables = 0;
|
||||
deletable_wiimotes = (wiimote_t**) malloc(sizeof(struct wiimote_t*) * (number_previous_wiimotes-number_merged_wiimotes));
|
||||
memset(deletable_wiimotes,0,sizeof(struct wiimote_t*) * (number_previous_wiimotes-number_merged_wiimotes));
|
||||
for (int i = 0; i < number_previous_wiimotes; i++)
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "karts/kart_properties.hpp"
|
||||
#include "modes/three_strikes_battle.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "network/rewind_manager.hpp"
|
||||
#include "physics/triangle_mesh.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
#include "physics/triangle_mesh.hpp"
|
||||
@ -45,6 +46,7 @@
|
||||
/** Initialises the attachment each kart has.
|
||||
*/
|
||||
Attachment::Attachment(AbstractKart* kart)
|
||||
: EventRewinder()
|
||||
{
|
||||
m_type = ATTACH_NOTHING;
|
||||
m_time_left = 0.0;
|
||||
@ -106,7 +108,7 @@ void Attachment::set(AttachmentType type, float time,
|
||||
{
|
||||
bool was_bomb = (m_type == ATTACH_BOMB);
|
||||
scene::ISceneNode* bomb_scene_node = NULL;
|
||||
if (was_bomb && type == ATTACH_SWATTER) //What about ATTACH_NOLOKS_SWATTER ??
|
||||
if (was_bomb && type == ATTACH_SWATTER)
|
||||
{
|
||||
// let's keep the bomb node, and create a new one for
|
||||
// the new attachment
|
||||
@ -182,6 +184,15 @@ void Attachment::set(AttachmentType type, float time,
|
||||
m_node->setVisible(true);
|
||||
|
||||
irr_driver->applyObjectPassShader(m_node);
|
||||
|
||||
// Save event about the new attachment
|
||||
RewindManager *rwm = RewindManager::get();
|
||||
if(rwm->isEnabled() && !rwm->isRewinding())
|
||||
{
|
||||
BareNetworkString *buffer = new BareNetworkString(2);
|
||||
saveState(buffer);
|
||||
rwm->addEvent(this, buffer);
|
||||
}
|
||||
} // set
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -216,6 +227,76 @@ void Attachment::clear()
|
||||
m_kart->updateWeight();
|
||||
} // clear
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/** Saves the attachment state. Called as part of the kart saving its state.
|
||||
* \param buffer The kart rewinder's state buffer.
|
||||
*/
|
||||
void Attachment::saveState(BareNetworkString *buffer) const
|
||||
{
|
||||
// We use bit 7 to indicate if a previous owner is defined for a bomb
|
||||
assert(ATTACH_MAX<=127);
|
||||
uint8_t type = m_type | (( (m_type==ATTACH_BOMB) && (m_previous_owner!=NULL) )
|
||||
? 0x80 : 0 );
|
||||
buffer->addUInt8(type);
|
||||
if(m_type!=ATTACH_NOTHING)
|
||||
{
|
||||
buffer->addFloat(m_time_left);
|
||||
if(m_type==ATTACH_BOMB && m_previous_owner)
|
||||
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
|
||||
}
|
||||
} // saveState
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/** Called from the kart rewinder when resetting to a certain state.
|
||||
* \param buffer The kart rewinder's buffer with the attachment state next.
|
||||
*/
|
||||
void Attachment::rewindTo(BareNetworkString *buffer)
|
||||
{
|
||||
uint8_t type = buffer->getUInt8();
|
||||
AttachmentType new_type = AttachmentType(type & 0x7f); // mask out bit 7
|
||||
|
||||
// If there is no attachment, clear the attachment if necessary and exit
|
||||
if(new_type==ATTACH_NOTHING)
|
||||
{
|
||||
if(m_type!=new_type) clear();
|
||||
return;
|
||||
}
|
||||
|
||||
float time_left = buffer->getFloat();
|
||||
|
||||
// Attaching an object can be expensive (loading new models, ...)
|
||||
// so avoid doing this if there is no change in attachment type
|
||||
if(new_type == m_type)
|
||||
{
|
||||
setTimeLeft(time_left);
|
||||
return;
|
||||
}
|
||||
|
||||
// Now it is a new attachment:
|
||||
|
||||
if (type == (ATTACH_BOMB | 0x80)) // we have previous owner information
|
||||
{
|
||||
uint8_t kart_id = buffer->getUInt8();
|
||||
m_previous_owner = World::getWorld()->getKart(kart_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_previous_owner = NULL;
|
||||
}
|
||||
set(new_type, time_left, m_previous_owner);
|
||||
} // rewindTo
|
||||
// -----------------------------------------------------------------------------
|
||||
/** Called when going forwards in time during a rewind.
|
||||
* \param buffer Buffer with the rewind information.
|
||||
*/
|
||||
void Attachment::rewind(BareNetworkString *buffer)
|
||||
{
|
||||
// Event has same info as a state, so re-use the restore function
|
||||
rewindTo(buffer);
|
||||
} // rewind
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/** Randomly selects the new attachment. For a server process, the
|
||||
* attachment can be passed into this function.
|
||||
@ -440,9 +521,13 @@ void Attachment::update(float dt)
|
||||
case ATTACH_MAX:
|
||||
break;
|
||||
case ATTACH_SWATTER:
|
||||
case ATTACH_NOLOKS_SWATTER:
|
||||
// Everything is done in the plugin.
|
||||
break;
|
||||
case ATTACH_NOLOKS_SWATTER:
|
||||
// Should never be called, this symbols is only used as an index for
|
||||
// the model, Nolok's attachment type is ATTACH_SWATTER
|
||||
assert(false);
|
||||
break;
|
||||
case ATTACH_BOMB:
|
||||
|
||||
if (m_bomb_sound) m_bomb_sound->setPosition(m_kart->getXYZ());
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
#include "config/stk_config.hpp"
|
||||
#include "items/attachment_plugin.hpp"
|
||||
#include "network/event_rewinder.hpp"
|
||||
#include "utils/no_copy.hpp"
|
||||
#include "utils/random_generator.hpp"
|
||||
|
||||
@ -28,6 +29,7 @@
|
||||
using namespace irr;
|
||||
|
||||
class AbstractKart;
|
||||
class BareNetworkString;
|
||||
class Item;
|
||||
class SFXBase;
|
||||
|
||||
@ -44,7 +46,8 @@ class SFXBase;
|
||||
* a scene node).
|
||||
* \ingroup items
|
||||
*/
|
||||
class Attachment: public NoCopy, public scene::IAnimationEndCallBack
|
||||
class Attachment: public NoCopy, public scene::IAnimationEndCallBack,
|
||||
public EventRewinder
|
||||
{
|
||||
public:
|
||||
// Some loop in attachment.cpp depend on ATTACH_FIRST and ATTACH_MAX.
|
||||
@ -57,6 +60,8 @@ public:
|
||||
ATTACH_BOMB,
|
||||
ATTACH_ANVIL,
|
||||
ATTACH_SWATTER,
|
||||
// Note that the next symbol is only used as an index into the mesh
|
||||
// array; it will NEVER be actually assigned as an attachment type
|
||||
ATTACH_NOLOKS_SWATTER,
|
||||
ATTACH_TINYTUX,
|
||||
ATTACH_BUBBLEGUM_SHIELD,
|
||||
@ -111,6 +116,9 @@ public:
|
||||
void handleCollisionWithKart(AbstractKart *other);
|
||||
void set (AttachmentType type, float time,
|
||||
AbstractKart *previous_kart=NULL);
|
||||
virtual void rewind(BareNetworkString *buffer);
|
||||
void rewindTo(BareNetworkString *buffer);
|
||||
void saveState(BareNetworkString *buffer) const;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets the type of the attachment, but keeps the old time left value. */
|
||||
@ -137,6 +145,10 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
/** 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) { }
|
||||
}; // Attachment
|
||||
|
||||
#endif
|
||||
|
@ -41,7 +41,7 @@ Bowling::Bowling(AbstractKart *kart)
|
||||
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().m_look_back )
|
||||
if( kart->getControls().getLookBack())
|
||||
{
|
||||
y_offset = -y_offset;
|
||||
m_speed = -m_speed*2;
|
||||
|
@ -67,7 +67,7 @@ Cake::Cake (AbstractKart *kart) : Flyable(kart, PowerupManager::POWERUP_CAKE)
|
||||
float pitch = kart->getTerrainPitch(heading);
|
||||
|
||||
// Find closest kart in front of the current one
|
||||
const bool backwards = kart->getControls().m_look_back;
|
||||
const bool backwards = kart->getControls().getLookBack();
|
||||
const AbstractKart *closest_kart=NULL;
|
||||
Vec3 direction;
|
||||
float kart_dist_squared;
|
||||
|
@ -25,11 +25,6 @@
|
||||
* Defines the various collectibles and weapons of STK.
|
||||
*/
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace scene { class IMesh; class ISceneNode; }
|
||||
}
|
||||
using namespace irr;
|
||||
|
||||
#include "utils/leak_check.hpp"
|
||||
#include "utils/no_copy.hpp"
|
||||
@ -38,8 +33,14 @@ using namespace irr;
|
||||
#include <line2d.h>
|
||||
|
||||
class AbstractKart;
|
||||
class LODNode;
|
||||
class Item;
|
||||
class LODNode;
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace scene { class IMesh; class ISceneNode; }
|
||||
}
|
||||
using namespace irr;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
|
@ -48,7 +48,7 @@ Plunger::Plunger(AbstractKart *kart)
|
||||
float plunger_speed = 2 * m_speed;
|
||||
|
||||
// if the kart is looking backwards, release from the back
|
||||
m_reverse_mode = kart->getControls().m_look_back;
|
||||
m_reverse_mode = kart->getControls().getLookBack();
|
||||
|
||||
// find closest kart in front of the current one
|
||||
const AbstractKart *closest_kart=0;
|
||||
|
@ -43,8 +43,8 @@
|
||||
*/
|
||||
Powerup::Powerup(AbstractKart* kart)
|
||||
{
|
||||
m_owner = kart;
|
||||
m_sound_use = NULL;
|
||||
m_kart = kart;
|
||||
m_sound_use = NULL;
|
||||
reset();
|
||||
} // Powerup
|
||||
|
||||
@ -69,6 +69,45 @@ void Powerup::reset()
|
||||
set( (PowerupManager::PowerupType)type, number );
|
||||
} // reset
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Save the powerup state. Called from the kart rewinder when saving the kart
|
||||
* state or when a new powerup even is saved.
|
||||
* \param buffer The buffer into which to save the state.
|
||||
*/
|
||||
void Powerup::saveState(BareNetworkString *buffer) const
|
||||
{
|
||||
buffer->addUInt8(uint8_t(m_type));
|
||||
if(m_type!=PowerupManager::POWERUP_NOTHING)
|
||||
{
|
||||
buffer->addUInt8(m_number); // number is <=255
|
||||
}
|
||||
} // saveState
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Restore a powerup state. Called from the kart rewinder when restoring a
|
||||
* state.
|
||||
* \param buffer Buffer with the state of this powerup object.
|
||||
*/
|
||||
void Powerup::rewindTo(BareNetworkString *buffer)
|
||||
{
|
||||
PowerupManager::PowerupType new_type =
|
||||
PowerupManager::PowerupType(buffer->getUInt8());
|
||||
int n=0;
|
||||
if(new_type==PowerupManager::POWERUP_NOTHING)
|
||||
{
|
||||
set(new_type, 0);
|
||||
return;
|
||||
}
|
||||
n = buffer->getUInt8();
|
||||
if(m_type == new_type)
|
||||
m_number = n;
|
||||
else
|
||||
{
|
||||
m_number = 0;
|
||||
set(new_type, n);
|
||||
}
|
||||
} // rewindTo
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Sets the collected items. The number of items is increased if the same
|
||||
* item is currently collected, otherwise replaces the existing item. It also
|
||||
@ -81,9 +120,15 @@ void Powerup::set(PowerupManager::PowerupType type, int n)
|
||||
if (m_type==type)
|
||||
{
|
||||
m_number+=n;
|
||||
// Limit to 255 (save space in network state saving)
|
||||
if(m_number>255) m_number = 255;
|
||||
return;
|
||||
}
|
||||
m_type=type;
|
||||
|
||||
// Limit to 255 (save space in network state saving)
|
||||
if(n>255) n = 255;
|
||||
|
||||
m_number=n;
|
||||
|
||||
if(m_sound_use != NULL)
|
||||
@ -147,14 +192,14 @@ Material *Powerup::getIcon() const
|
||||
*/
|
||||
void Powerup::adjustSound()
|
||||
{
|
||||
m_sound_use->setPosition(m_owner->getXYZ());
|
||||
m_sound_use->setPosition(m_kart->getXYZ());
|
||||
// in multiplayer mode, sounds are NOT positional (because we have multiple listeners)
|
||||
// so the sounds of all AIs are constantly heard. So reduce volume of sounds.
|
||||
if (race_manager->getNumLocalPlayers() > 1)
|
||||
{
|
||||
// player karts played at full volume; AI karts much dimmer
|
||||
|
||||
if (m_owner->getController()->isLocalPlayerController())
|
||||
if (m_kart->getController()->isLocalPlayerController())
|
||||
{
|
||||
m_sound_use->setVolume( 1.0f );
|
||||
}
|
||||
@ -171,11 +216,11 @@ void Powerup::adjustSound()
|
||||
*/
|
||||
void Powerup::use()
|
||||
{
|
||||
const KartProperties *kp = m_owner->getKartProperties();
|
||||
const KartProperties *kp = m_kart->getKartProperties();
|
||||
|
||||
// The player gets an achievement point for using a powerup
|
||||
if (m_type != PowerupManager::POWERUP_NOTHING &&
|
||||
m_owner->getController()->canGetAchievements() )
|
||||
m_kart->getController()->canGetAchievements() )
|
||||
{
|
||||
PlayerManager::increaseAchievement(AchievementInfo::ACHIEVE_POWERUP_LOVER, "poweruplover");
|
||||
}
|
||||
@ -184,7 +229,7 @@ void Powerup::use()
|
||||
if (m_type != PowerupManager::POWERUP_NOTHING &&
|
||||
m_type != PowerupManager::POWERUP_SWATTER &&
|
||||
m_type != PowerupManager::POWERUP_ZIPPER)
|
||||
m_owner->playCustomSFX(SFXManager::CUSTOM_SHOOT);
|
||||
m_kart->playCustomSFX(SFXManager::CUSTOM_SHOOT);
|
||||
|
||||
// FIXME - for some collectibles, set() is never called
|
||||
if(m_sound_use == NULL)
|
||||
@ -199,12 +244,12 @@ void Powerup::use()
|
||||
switch (m_type)
|
||||
{
|
||||
case PowerupManager::POWERUP_ZIPPER:
|
||||
m_owner->handleZipper(NULL, true);
|
||||
m_kart->handleZipper(NULL, true);
|
||||
break ;
|
||||
case PowerupManager::POWERUP_SWITCH:
|
||||
{
|
||||
ItemManager::get()->switchItems();
|
||||
m_sound_use->setPosition(m_owner->getXYZ());
|
||||
m_sound_use->setPosition(m_kart->getXYZ());
|
||||
m_sound_use->play();
|
||||
break;
|
||||
}
|
||||
@ -213,28 +258,29 @@ void Powerup::use()
|
||||
case PowerupManager::POWERUP_BOWLING:
|
||||
case PowerupManager::POWERUP_PLUNGER:
|
||||
if(stk_config->m_shield_restrict_weapos)
|
||||
m_owner->setShieldTime(0.0f); // make weapon usage destroy the shield
|
||||
m_kart->setShieldTime(0.0f); // make weapon usage destroy the shield
|
||||
Powerup::adjustSound();
|
||||
m_sound_use->play();
|
||||
|
||||
projectile_manager->newProjectile(m_owner, m_type);
|
||||
projectile_manager->newProjectile(m_kart, m_type);
|
||||
break ;
|
||||
|
||||
case PowerupManager::POWERUP_SWATTER:
|
||||
m_owner->getAttachment()
|
||||
m_kart->getAttachment()
|
||||
->set(Attachment::ATTACH_SWATTER, kp->getSwatterDuration());
|
||||
break;
|
||||
|
||||
case PowerupManager::POWERUP_BUBBLEGUM:
|
||||
// use the bubble gum the traditional way, if the kart is looking back
|
||||
if (m_owner->getControls().m_look_back)
|
||||
if (m_kart->getControls().getLookBack())
|
||||
{
|
||||
Vec3 hit_point;
|
||||
Vec3 normal;
|
||||
const Material* material_hit;
|
||||
world->getTrack()->getTriangleMesh().castRay(m_owner->getXYZ(),
|
||||
m_owner->getTrans().getBasis() * Vec3(0, -10000, 0), &hit_point,
|
||||
&material_hit, &normal);
|
||||
Vec3 pos = m_kart->getXYZ();
|
||||
Vec3 to = pos+ m_kart->getTrans().getBasis() * Vec3(0, -10000, 0);
|
||||
world->getTrack()->getTriangleMesh().castRay(pos, to, &hit_point,
|
||||
&material_hit, &normal);
|
||||
// This can happen if the kart is 'over nothing' when dropping
|
||||
// the bubble gum
|
||||
if(!material_hit)
|
||||
@ -244,36 +290,36 @@ void Powerup::use()
|
||||
Powerup::adjustSound();
|
||||
m_sound_use->play();
|
||||
|
||||
Vec3 pos = hit_point + m_owner->getTrans().getBasis() * Vec3(0, -0.05f, 0);
|
||||
ItemManager::get()->newItem(Item::ITEM_BUBBLEGUM, pos, normal, m_owner);
|
||||
pos = hit_point + m_kart->getTrans().getBasis() * Vec3(0, -0.05f, 0);
|
||||
ItemManager::get()->newItem(Item::ITEM_BUBBLEGUM, pos, normal, m_kart);
|
||||
}
|
||||
else // if the kart is looking forward, use the bubblegum as a shield
|
||||
{
|
||||
|
||||
if(!m_owner->isShielded()) //if the previous shield had been used up.
|
||||
if(!m_kart->isShielded()) //if the previous shield had been used up.
|
||||
{
|
||||
if (m_owner->getIdent() == "nolok")
|
||||
if (m_kart->getIdent() == "nolok")
|
||||
{
|
||||
m_owner->getAttachment()->set(Attachment::ATTACH_NOLOK_BUBBLEGUM_SHIELD,
|
||||
m_kart->getAttachment()->set(Attachment::ATTACH_NOLOK_BUBBLEGUM_SHIELD,
|
||||
kp->getBubblegumShieldDuration());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_owner->getAttachment()->set(Attachment::ATTACH_BUBBLEGUM_SHIELD,
|
||||
m_kart->getAttachment()->set(Attachment::ATTACH_BUBBLEGUM_SHIELD,
|
||||
kp->getBubblegumShieldDuration());
|
||||
}
|
||||
}
|
||||
else // using a bubble gum while still having a shield
|
||||
{
|
||||
if (m_owner->getIdent() == "nolok")
|
||||
if (m_kart->getIdent() == "nolok")
|
||||
{
|
||||
m_owner->getAttachment()->set(Attachment::ATTACH_NOLOK_BUBBLEGUM_SHIELD,
|
||||
kp->getBubblegumShieldDuration() + m_owner->getShieldTime());
|
||||
m_kart->getAttachment()->set(Attachment::ATTACH_NOLOK_BUBBLEGUM_SHIELD,
|
||||
kp->getBubblegumShieldDuration() + m_kart->getShieldTime());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_owner->getAttachment()->set(Attachment::ATTACH_BUBBLEGUM_SHIELD,
|
||||
kp->getBubblegumShieldDuration() + m_owner->getShieldTime());
|
||||
m_kart->getAttachment()->set(Attachment::ATTACH_BUBBLEGUM_SHIELD,
|
||||
kp->getBubblegumShieldDuration() + m_kart->getShieldTime());
|
||||
}
|
||||
}
|
||||
|
||||
@ -293,7 +339,7 @@ void Powerup::use()
|
||||
{
|
||||
AbstractKart *kart=world->getKart(i);
|
||||
if(kart->isEliminated() || kart->isInvulnerable()) continue;
|
||||
if(kart == m_owner) continue;
|
||||
if(kart == m_kart) continue;
|
||||
if(kart->getPosition() == 1)
|
||||
{
|
||||
kart->getAttachment()->set(Attachment::ATTACH_ANVIL,
|
||||
@ -308,7 +354,7 @@ void Powerup::use()
|
||||
if(kart->getController()->isLocalPlayerController())
|
||||
m_sound_use->setPosition(kart->getXYZ());
|
||||
else
|
||||
m_sound_use->setPosition(m_owner->getXYZ());
|
||||
m_sound_use->setPosition(m_kart->getXYZ());
|
||||
|
||||
m_sound_use->play();
|
||||
break;
|
||||
@ -326,13 +372,13 @@ void Powerup::use()
|
||||
for(unsigned int i = 0 ; i < world->getNumKarts(); ++i)
|
||||
{
|
||||
AbstractKart *kart=world->getKart(i);
|
||||
if(kart->isEliminated() || kart== m_owner || kart->isInvulnerable()) continue;
|
||||
if(kart->isEliminated() || kart== m_kart || kart->isInvulnerable()) continue;
|
||||
if(kart->isShielded())
|
||||
{
|
||||
kart->decreaseShieldTime();
|
||||
continue;
|
||||
}
|
||||
if(m_owner->getPosition() > kart->getPosition())
|
||||
if(m_kart->getPosition() > kart->getPosition())
|
||||
{
|
||||
kart->getAttachment()->set(Attachment::ATTACH_PARACHUTE,
|
||||
kp->getParachuteDurationOther());
|
||||
@ -346,8 +392,8 @@ void Powerup::use()
|
||||
// or the kart "throwing" the anvil? Ideally it should be both.
|
||||
// Meanwhile, don't play it near AI karts since they obviously
|
||||
// don't hear anything
|
||||
if(m_owner->getController()->isLocalPlayerController())
|
||||
m_sound_use->setPosition(m_owner->getXYZ());
|
||||
if(m_kart->getController()->isLocalPlayerController())
|
||||
m_sound_use->setPosition(m_kart->getXYZ());
|
||||
else if(player_kart)
|
||||
m_sound_use->setPosition(player_kart->getXYZ());
|
||||
m_sound_use->play();
|
||||
@ -356,8 +402,8 @@ void Powerup::use()
|
||||
|
||||
case PowerupManager::POWERUP_NOTHING:
|
||||
{
|
||||
if(!m_owner->getKartAnimation())
|
||||
m_owner->beep();
|
||||
if(!m_kart->getKartAnimation())
|
||||
m_kart->beep();
|
||||
}
|
||||
break;
|
||||
default : break;
|
||||
@ -387,7 +433,7 @@ void Powerup::hitBonusBox(const Item &item, int add_info)
|
||||
{
|
||||
// Position can be -1 in case of a battle mode (which doesn't have
|
||||
// positions), but this case is properly handled in getRandomPowerup.
|
||||
int position = m_owner->getPosition();
|
||||
int position = m_kart->getPosition();
|
||||
|
||||
unsigned int n=1;
|
||||
PowerupManager::PowerupType new_powerup;
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "utils/random_generator.hpp"
|
||||
|
||||
class AbstractKart;
|
||||
class BareNetworkString;
|
||||
class Item;
|
||||
class SFXBase;
|
||||
|
||||
@ -48,7 +49,7 @@ private:
|
||||
int m_number;
|
||||
|
||||
/** The owner (kart) of this powerup. */
|
||||
AbstractKart* m_owner;
|
||||
AbstractKart* m_kart;
|
||||
|
||||
public:
|
||||
Powerup (AbstractKart* kart_);
|
||||
@ -56,9 +57,12 @@ public:
|
||||
void set (PowerupManager::PowerupType _type, int n=1);
|
||||
void reset ();
|
||||
Material* getIcon () const;
|
||||
void adjustSound ();
|
||||
void adjustSound ();
|
||||
void use ();
|
||||
void hitBonusBox (const Item &item, int newC=-1);
|
||||
void saveState(BareNetworkString *buffer) const;
|
||||
void rewindTo(BareNetworkString *buffer);
|
||||
|
||||
|
||||
/** Returns the number of powerups. */
|
||||
int getNum () const {return m_number;}
|
||||
|
@ -19,20 +19,19 @@
|
||||
#ifndef HEADER_POWERUPMANAGER_HPP
|
||||
#define HEADER_POWERUPMANAGER_HPP
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace scene { class IMesh; }
|
||||
}
|
||||
#include "utils/no_copy.hpp"
|
||||
|
||||
#include "btBulletDynamicsCommon.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "btBulletDynamicsCommon.h"
|
||||
|
||||
#include "utils/no_copy.hpp"
|
||||
|
||||
class Material;
|
||||
class XMLNode;
|
||||
namespace irr
|
||||
{
|
||||
namespace scene { class IMesh; }
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup items
|
||||
|
@ -110,16 +110,13 @@ public:
|
||||
// Functions related to controlling the kart
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the current steering value for this kart. */
|
||||
float getSteerPercent() const { return m_controls.m_steer; }
|
||||
float getSteerPercent() const { return m_controls.getSteer(); }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns all controls of this kart. */
|
||||
KartControl& getControls() { return m_controls; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns all controls of this kart - const version. */
|
||||
const KartControl& getControls() const { return m_controls; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets the kart controls. Used e.g. by replaying history. */
|
||||
void setControls(const KartControl &c) { m_controls = c; }
|
||||
|
||||
// ========================================================================
|
||||
// Access to the kart properties.
|
||||
@ -278,6 +275,10 @@ public:
|
||||
* like Ghost. */
|
||||
virtual float getSpeed() const = 0;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the exponentially smoothened speed of the kart in
|
||||
* which is removes shaking from camera. */
|
||||
virtual float getSmoothedSpeed() const = 0;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the current maximum speed for this kart, this includes all
|
||||
* bonus and maluses that are currently applied. */
|
||||
virtual float getCurrentMaxSpeed() const = 0;
|
||||
|
@ -184,11 +184,11 @@ void AIBaseController::setSteering(float angle, float dt)
|
||||
{
|
||||
float steer_fraction = angle / m_kart->getMaxSteerAngle();
|
||||
if(!canSkid(steer_fraction))
|
||||
m_controls->m_skid = KartControl::SC_NONE;
|
||||
m_controls->setSkidControl(KartControl::SC_NONE);
|
||||
else
|
||||
m_controls->m_skid = steer_fraction > 0 ? KartControl::SC_RIGHT
|
||||
: KartControl::SC_LEFT;
|
||||
float old_steer = m_controls->m_steer;
|
||||
m_controls->setSkidControl(steer_fraction > 0 ? KartControl::SC_RIGHT
|
||||
: KartControl::SC_LEFT );
|
||||
float old_steer = m_controls->getSteer();
|
||||
|
||||
if (steer_fraction > 1.0f) steer_fraction = 1.0f;
|
||||
else if(steer_fraction < -1.0f) steer_fraction = -1.0f;
|
||||
@ -203,13 +203,13 @@ void AIBaseController::setSteering(float angle, float dt)
|
||||
float max_steer_change = dt/m_ai_properties->m_time_full_steer;
|
||||
if(old_steer < steer_fraction)
|
||||
{
|
||||
m_controls->m_steer = (old_steer+max_steer_change > steer_fraction)
|
||||
? steer_fraction : old_steer+max_steer_change;
|
||||
m_controls->setSteer(( old_steer+max_steer_change > steer_fraction)
|
||||
? steer_fraction : old_steer+max_steer_change);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_controls->m_steer = (old_steer-max_steer_change < steer_fraction)
|
||||
? steer_fraction : old_steer-max_steer_change;
|
||||
m_controls->setSteer( (old_steer-max_steer_change < steer_fraction)
|
||||
? steer_fraction : old_steer-max_steer_change );
|
||||
}
|
||||
} // setSteering
|
||||
|
||||
|
@ -78,8 +78,8 @@ void ArenaAI::reset()
|
||||
void ArenaAI::update(float dt)
|
||||
{
|
||||
// This is used to enable firing an item backwards.
|
||||
m_controls->m_look_back = false;
|
||||
m_controls->m_nitro = false;
|
||||
m_controls->setLookBack(false);
|
||||
m_controls->setNitro(false);
|
||||
|
||||
// Don't do anything if there is currently a kart animations shown.
|
||||
if (m_kart->getKartAnimation())
|
||||
@ -129,8 +129,8 @@ void ArenaAI::update(float dt)
|
||||
if (m_kart->getSpeed() > 15.0f && !m_is_uturn && m_turn_radius > 30.0f &&
|
||||
!ignorePathFinding())
|
||||
{
|
||||
// Only use nitro when turn radius is large
|
||||
m_controls->m_nitro = true;
|
||||
// Only use nitro when turn angle is big (180 - angle)
|
||||
m_controls->setNitro(true);
|
||||
}
|
||||
|
||||
if (m_is_uturn)
|
||||
@ -323,27 +323,27 @@ void ArenaAI::checkIfStuck(const float dt)
|
||||
*/
|
||||
void ArenaAI::configSpeed()
|
||||
{
|
||||
m_controls->m_accel = 0.0f;
|
||||
m_controls->m_brake = false;
|
||||
m_controls->setAccel(0.0f);
|
||||
m_controls->setBrake(false);
|
||||
|
||||
// A kart will not brake when the speed is already slower than this
|
||||
// value. This prevents a kart from going too slow (or even backwards)
|
||||
// in tight curves.
|
||||
|
||||
const float MIN_SPEED = 5.0f;
|
||||
const float handicap =
|
||||
(m_cur_difficulty == RaceManager::DIFFICULTY_EASY ? 0.7f : 1.0f);
|
||||
const float handicap = (m_cur_difficulty == RaceManager::DIFFICULTY_EASY
|
||||
? 0.7f : 1.0f );
|
||||
|
||||
const float max_turn_speed = m_kart->getSpeedForTurnRadius(m_turn_radius);
|
||||
if ((m_kart->getSpeed() > max_turn_speed || forceBraking()) &&
|
||||
m_kart->getSpeed() > MIN_SPEED * handicap)
|
||||
{
|
||||
// Brake if necessary
|
||||
m_controls->m_brake = true;
|
||||
m_controls->setBrake(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise accelerate
|
||||
m_controls->m_accel = stk_config->m_ai_acceleration * handicap;
|
||||
m_controls->setAccel(stk_config->m_ai_acceleration * handicap);
|
||||
}
|
||||
} // configSpeed
|
||||
|
||||
@ -355,9 +355,9 @@ void ArenaAI::doUTurn(const float dt)
|
||||
if (fabsf(m_kart->getSpeed()) >
|
||||
(m_kart->getKartProperties()->getEngineMaxSpeed() / 5)
|
||||
&& m_kart->getSpeed() < 0) // Try to emulate reverse like human players
|
||||
m_controls->m_accel = -0.06f;
|
||||
m_controls->setAccel(-0.06f);
|
||||
else
|
||||
m_controls->m_accel = -5.0f;
|
||||
m_controls->setAccel(-5.0f);
|
||||
|
||||
if (m_time_since_uturn >=
|
||||
(m_cur_difficulty == RaceManager::DIFFICULTY_EASY ? 2.0f : 1.5f))
|
||||
@ -389,9 +389,9 @@ bool ArenaAI::gettingUnstuck(const float dt)
|
||||
if (fabsf(m_kart->getSpeed()) >
|
||||
(m_kart->getKartProperties()->getEngineMaxSpeed() / 5)
|
||||
&& m_kart->getSpeed() < 0)
|
||||
m_controls->m_accel = -0.06f;
|
||||
m_controls->setAccel(-0.06f);
|
||||
else
|
||||
m_controls->m_accel = -4.0f;
|
||||
m_controls->setAccel(-4.0f);
|
||||
|
||||
m_time_since_reversing += dt;
|
||||
|
||||
@ -408,7 +408,7 @@ bool ArenaAI::gettingUnstuck(const float dt)
|
||||
//-----------------------------------------------------------------------------
|
||||
void ArenaAI::useItems(const float dt)
|
||||
{
|
||||
m_controls->m_fire = false;
|
||||
m_controls->setFire(false);
|
||||
if (m_kart->getKartAnimation() ||
|
||||
m_kart->getPowerup()->getType() == PowerupManager::POWERUP_NOTHING)
|
||||
return;
|
||||
@ -443,24 +443,21 @@ void ArenaAI::useItems(const float dt)
|
||||
{
|
||||
Attachment::AttachmentType type = m_kart->getAttachment()->getType();
|
||||
// Don't use shield when we have a swatter.
|
||||
if (type == Attachment::ATTACH_SWATTER ||
|
||||
type == Attachment::ATTACH_NOLOKS_SWATTER)
|
||||
if (type == Attachment::ATTACH_SWATTER)
|
||||
break;
|
||||
|
||||
// Check if a flyable (cake, ...) is close or a kart nearby
|
||||
// has a swatter attachment. If so, use bubblegum
|
||||
// as shield
|
||||
if ((!m_kart->isShielded() &&
|
||||
projectile_manager->projectileIsClose(m_kart,
|
||||
m_ai_properties->m_shield_incoming_radius)) ||
|
||||
(dist_to_kart < 15.0f &&
|
||||
((m_closest_kart->getAttachment()->
|
||||
getType() == Attachment::ATTACH_SWATTER) ||
|
||||
(m_closest_kart->getAttachment()->
|
||||
getType() == Attachment::ATTACH_NOLOKS_SWATTER))))
|
||||
if ( (!m_kart->isShielded() &&
|
||||
projectile_manager->projectileIsClose(m_kart,
|
||||
m_ai_properties->m_shield_incoming_radius) ) ||
|
||||
(dist_to_kart < 15.0f &&
|
||||
(m_closest_kart->getAttachment()->
|
||||
getType() == Attachment::ATTACH_SWATTER) ) )
|
||||
{
|
||||
m_controls->m_fire = true;
|
||||
m_controls->m_look_back = false;
|
||||
m_controls->setFire(true);
|
||||
m_controls->setLookBack(false);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -471,8 +468,8 @@ void ArenaAI::useItems(const float dt)
|
||||
// or can't find a close kart for too long time
|
||||
if (dist_to_kart < 15.0f || m_time_since_last_shot > 15.0f)
|
||||
{
|
||||
m_controls->m_fire = true;
|
||||
m_controls->m_look_back = true;
|
||||
m_controls->setFire(true);
|
||||
m_controls->setLookBack(true);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -490,8 +487,8 @@ void ArenaAI::useItems(const float dt)
|
||||
if (dist_to_kart < 25.0f &&
|
||||
!m_closest_kart->isInvulnerable())
|
||||
{
|
||||
m_controls->m_fire = true;
|
||||
m_controls->m_look_back = fire_behind;
|
||||
m_controls->setFire(true);
|
||||
m_controls->setLookBack(fire_behind);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -511,8 +508,8 @@ void ArenaAI::useItems(const float dt)
|
||||
(difficulty || perfect_aim) &&
|
||||
!m_closest_kart->isInvulnerable())
|
||||
{
|
||||
m_controls->m_fire = true;
|
||||
m_controls->m_look_back = fire_behind;
|
||||
m_controls->setFire(true);
|
||||
m_controls->setLookBack(fire_behind);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -531,8 +528,8 @@ void ArenaAI::useItems(const float dt)
|
||||
dist_to_kart * dist_to_kart < d2 &&
|
||||
m_closest_kart->getSpeed() < m_kart->getSpeed())
|
||||
{
|
||||
m_controls->m_fire = true;
|
||||
m_controls->m_look_back = false;
|
||||
m_controls->setFire(true);
|
||||
m_controls->setLookBack(false);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -546,7 +543,7 @@ void ArenaAI::useItems(const float dt)
|
||||
break; // POWERUP_PLUNGER
|
||||
|
||||
case PowerupManager::POWERUP_SWITCH: // Don't handle switch
|
||||
m_controls->m_fire = true; // (use it no matter what) for now
|
||||
m_controls->setFire(true); // (use it no matter what) for now
|
||||
break; // POWERUP_SWITCH
|
||||
|
||||
case PowerupManager::POWERUP_PARACHUTE:
|
||||
@ -564,7 +561,7 @@ void ArenaAI::useItems(const float dt)
|
||||
m_kart->getPowerup()->getType());
|
||||
assert(false);
|
||||
}
|
||||
if (m_controls->m_fire)
|
||||
if (m_controls->getFire())
|
||||
m_time_since_last_shot = 0.0f;
|
||||
} // useItems
|
||||
|
||||
|
@ -175,10 +175,10 @@ void EndController::action(PlayerAction action, int value)
|
||||
void EndController::update(float dt)
|
||||
{
|
||||
// This is used to enable firing an item backwards.
|
||||
m_controls->m_look_back = false;
|
||||
m_controls->m_nitro = false;
|
||||
m_controls->m_brake = false;
|
||||
m_controls->m_accel = 1.0f;
|
||||
m_controls->setLookBack(false);
|
||||
m_controls->setNitro(false);
|
||||
m_controls->setBrake(false);
|
||||
m_controls->setAccel(1.0f);
|
||||
|
||||
AIBaseLapController::update(dt);
|
||||
|
||||
@ -187,10 +187,10 @@ void EndController::update(float dt)
|
||||
race_manager->getMinorMode()==RaceManager::MINOR_MODE_SOCCER ||
|
||||
race_manager->getMinorMode()==RaceManager::MINOR_MODE_EASTER_EGG)
|
||||
{
|
||||
m_controls->m_accel = 0.0f;
|
||||
m_controls->setAccel(0.0f);
|
||||
// Brake while we are still driving forwards (if we keep
|
||||
// on braking, the kart will reverse otherwise)
|
||||
m_controls->m_brake = m_kart->getSpeed()>0;
|
||||
m_controls->setBrake(m_kart->getSpeed()>0);
|
||||
return;
|
||||
}
|
||||
/*Get information that is needed by more than 1 of the handling funcs*/
|
||||
@ -260,26 +260,24 @@ void EndController::handleRescue(const float DELTA)
|
||||
void EndController::findNonCrashingPoint(Vec3 *result)
|
||||
{
|
||||
unsigned int sector = m_next_node_index[m_track_node];
|
||||
int target_sector;
|
||||
|
||||
Vec3 direction;
|
||||
Vec3 step_track_coord;
|
||||
float distance;
|
||||
int steps;
|
||||
|
||||
//We exit from the function when we have found a solution
|
||||
while( 1 )
|
||||
{
|
||||
//target_sector is the sector at the longest distance that we can drive
|
||||
//to without crashing with the track.
|
||||
target_sector = m_next_node_index[sector];
|
||||
int target_sector = m_next_node_index[sector];
|
||||
|
||||
//direction is a vector from our kart to the sectors we are testing
|
||||
direction = DriveGraph::get()->getNode(target_sector)->getCenter()
|
||||
- m_kart->getXYZ();
|
||||
|
||||
float len=direction.length();
|
||||
steps = int( len / m_kart_length );
|
||||
int steps = int( len / m_kart_length );
|
||||
if( steps < 3 ) steps = 3;
|
||||
|
||||
//Protection against having vel_normal with nan values
|
||||
|
@ -54,7 +54,7 @@ void GhostController::update(float dt)
|
||||
if(camera->getKart()!=m_kart) continue;
|
||||
if (camera->getType() != Camera::CM_TYPE_END)
|
||||
{
|
||||
if (m_controls->m_look_back)
|
||||
if (m_controls->getLookBack())
|
||||
{
|
||||
camera->setMode(Camera::CM_REVERSE);
|
||||
}
|
||||
@ -85,5 +85,5 @@ void GhostController::action(PlayerAction action, int value)
|
||||
{
|
||||
// Watching replay use only
|
||||
if (action == PA_LOOK_BACK)
|
||||
m_controls->m_look_back = (value!=0);
|
||||
m_controls->setLookBack(value!=0);
|
||||
} // action
|
||||
|
185
src/karts/controller/kart_control.cpp
Normal file
185
src/karts/controller/kart_control.cpp
Normal file
@ -0,0 +1,185 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2008-2016 Joerg Henrichs
|
||||
//
|
||||
// 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 "karts/controller/kart_control.hpp"
|
||||
|
||||
#include "network/rewind_manager.hpp"
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Called when going back in time during a rewind. Nothing to do here
|
||||
* in this case.
|
||||
*/
|
||||
void KartControl::undo(BareNetworkString *buffer)
|
||||
{
|
||||
} // undo
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Replay an event for a KartControl object from the buffer.
|
||||
* \param buffer BareNetworkString with saved event into.
|
||||
*/
|
||||
void KartControl::rewind(BareNetworkString *buffer)
|
||||
{
|
||||
if(buffer->getTotalSize()>1)
|
||||
{
|
||||
// Full state including accel and steering was saved
|
||||
setFromBuffer(buffer);
|
||||
}
|
||||
else // only a button event was stored
|
||||
{
|
||||
setButtonsCompressed(buffer->getUInt8());
|
||||
}
|
||||
} // rewind
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets this KartControl form the given value (basically a copy). This
|
||||
* function uses the explicit setSteer() etc function, which means that
|
||||
* rewind information will be collected.
|
||||
*/
|
||||
void KartControl::set(const KartControl &c)
|
||||
{
|
||||
setAccel(c.getAccel());
|
||||
setBrake(c.getBrake());
|
||||
setFire(c.getFire());
|
||||
setLookBack(c.getLookBack());
|
||||
setNitro(c.getNitro());
|
||||
setRescue(c.getRescue());
|
||||
setSkidControl(c.getSkidControl());
|
||||
setSteer(c.getSteer());
|
||||
} // set
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets the current steering value. */
|
||||
void KartControl::setSteer(float f)
|
||||
{
|
||||
float old_steer = m_steer;
|
||||
m_steer = f;
|
||||
if (RewindManager::isEnabled() && !RewindManager::get()->isRewinding() &&
|
||||
old_steer != m_steer )
|
||||
{
|
||||
// Save full status
|
||||
BareNetworkString *buffer = new BareNetworkString(getLength());
|
||||
copyToBuffer(buffer);
|
||||
RewindManager::get()->addEvent(this, buffer);
|
||||
}
|
||||
} // setSteer
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Sets the acceleration. */
|
||||
void KartControl::setAccel(float f)
|
||||
{
|
||||
float old_accel = m_accel;
|
||||
m_accel = f;
|
||||
if (RewindManager::isEnabled() && !RewindManager::get()->isRewinding() &&
|
||||
old_accel != m_accel )
|
||||
{
|
||||
BareNetworkString *buffer = new BareNetworkString(getLength());
|
||||
copyToBuffer(buffer);
|
||||
RewindManager::get()->addEvent(this, buffer);
|
||||
}
|
||||
} // setAccel
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Sets if the kart is braking. */
|
||||
void KartControl::setBrake(bool b)
|
||||
{
|
||||
bool old_brake = m_brake;
|
||||
m_brake = b;
|
||||
if (RewindManager::isEnabled() && !RewindManager::get()->isRewinding() &&
|
||||
old_brake != m_brake )
|
||||
{
|
||||
// Only store the buttons in this case
|
||||
BareNetworkString *buffer = new BareNetworkString(1);
|
||||
buffer->addUInt8(getButtonsCompressed());
|
||||
RewindManager::get()->addEvent(this, buffer);
|
||||
}
|
||||
} // setBrake
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Sets if the kart activates nitro. */
|
||||
void KartControl::setNitro(bool b)
|
||||
{
|
||||
bool old_nitro = m_nitro;
|
||||
m_nitro = b;
|
||||
if (RewindManager::isEnabled() && !RewindManager::get()->isRewinding() &&
|
||||
old_nitro != m_nitro )
|
||||
{
|
||||
BareNetworkString *buffer = new BareNetworkString(1);
|
||||
buffer->addUInt8(getButtonsCompressed());
|
||||
RewindManager::get()->addEvent(this, buffer);
|
||||
}
|
||||
} // setNitro
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Sets the skid control for this kart. */
|
||||
void KartControl::setSkidControl(SkidControl sc)
|
||||
{
|
||||
SkidControl old_skid = m_skid;
|
||||
m_skid = sc;
|
||||
if (RewindManager::isEnabled() && !RewindManager::get()->isRewinding() &&
|
||||
old_skid != m_skid )
|
||||
{
|
||||
BareNetworkString *buffer = new BareNetworkString(1);
|
||||
buffer->addUInt8(getButtonsCompressed());
|
||||
RewindManager::get()->addEvent(this, buffer);
|
||||
}
|
||||
} // seSkidControl
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Returns if this kart wants to get rescued. */
|
||||
void KartControl::setRescue(bool b)
|
||||
{
|
||||
bool old_rescue = m_rescue;
|
||||
m_rescue = b;
|
||||
if (RewindManager::isEnabled() && !RewindManager::get()->isRewinding() &&
|
||||
old_rescue != m_rescue)
|
||||
{
|
||||
BareNetworkString *buffer = new BareNetworkString(1);
|
||||
buffer->addUInt8(getButtonsCompressed());
|
||||
RewindManager::get()->addEvent(this, buffer);
|
||||
}
|
||||
} // setRescue
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Sets if the kart wants to fire. */
|
||||
void KartControl::setFire(bool b)
|
||||
{
|
||||
bool old_fire = m_fire;
|
||||
m_fire = b;
|
||||
if (RewindManager::isEnabled() && !RewindManager::get()->isRewinding() &&
|
||||
old_fire != m_fire )
|
||||
{
|
||||
BareNetworkString *buffer = new BareNetworkString(1);
|
||||
buffer->addUInt8(getButtonsCompressed());
|
||||
RewindManager::get()->addEvent(this, buffer);
|
||||
}
|
||||
} // setFire
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Sets if the kart wants to look (and therefore also fires) backwards. */
|
||||
void KartControl::setLookBack(bool b)
|
||||
{
|
||||
bool old_look = m_look_back;
|
||||
m_look_back = b;
|
||||
if (RewindManager::isEnabled() && !RewindManager::get()->isRewinding() &&
|
||||
old_look != m_look_back)
|
||||
{
|
||||
BareNetworkString *buffer = new BareNetworkString(1);
|
||||
buffer->addUInt8(getButtonsCompressed());
|
||||
RewindManager::get()->addEvent(this, buffer);
|
||||
}
|
||||
} // setLookBack
|
@ -19,13 +19,21 @@
|
||||
#ifndef HEADER_KART_CONTROL_HPP
|
||||
#define HEADER_KART_CONTROL_HPP
|
||||
|
||||
#include "network/network_string.hpp"
|
||||
#include "network/rewind_info.hpp"
|
||||
|
||||
/**
|
||||
* \ingroup controller
|
||||
*/
|
||||
class KartControl
|
||||
class KartControl : public EventRewinder
|
||||
{
|
||||
public:
|
||||
/** The skidding control state: SC_NONE: not pressed;
|
||||
* SC_NO_DIRECTION: pressed, but no steering;
|
||||
* SC_LEFT/RIGHT: pressed in the specified direction. */
|
||||
enum SkidControl {SC_NONE, SC_NO_DIRECTION, SC_LEFT, SC_RIGHT};
|
||||
|
||||
private:
|
||||
/** The current steering value in [-1, 1]. */
|
||||
float m_steer;
|
||||
/** Acceleration, in [0, 1]. */
|
||||
@ -34,18 +42,28 @@ public:
|
||||
bool m_brake;
|
||||
/** True if the kart activates nitro. */
|
||||
bool m_nitro;
|
||||
/** The skidding control state: SC_NONE: not pressed;
|
||||
SC_NO_DIRECTION: pressed, but no steering;
|
||||
SC_LEFT/RIGHT: pressed in the specified direction. */
|
||||
enum SkidControl {SC_NONE, SC_NO_DIRECTION, SC_LEFT, SC_RIGHT}
|
||||
m_skid;
|
||||
/** Skidding control state. */
|
||||
SkidControl m_skid;
|
||||
/** True if rescue is selected. */
|
||||
bool m_rescue;
|
||||
/** True if fire is selected. */
|
||||
bool m_fire;
|
||||
/** True if the kart looks (and shoots) backwards. */
|
||||
bool m_look_back;
|
||||
public:
|
||||
virtual void undo(BareNetworkString *buffer);
|
||||
virtual void rewind(BareNetworkString *buffer);
|
||||
void setSteer(float f);
|
||||
void setAccel(float f);
|
||||
void setBrake(bool b);
|
||||
void setNitro(bool b);
|
||||
void setSkidControl(SkidControl sc);
|
||||
void setRescue(bool b);
|
||||
void setFire(bool b);
|
||||
void setLookBack(bool b);
|
||||
void set(const KartControl &c);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
KartControl()
|
||||
{
|
||||
reset();
|
||||
@ -64,14 +82,43 @@ public:
|
||||
m_look_back = false;
|
||||
} // reset
|
||||
// ------------------------------------------------------------------------
|
||||
void uncompress(char *c)
|
||||
/** Tests if two KartControls are equal.
|
||||
*/
|
||||
bool operator==(const KartControl &other)
|
||||
{
|
||||
m_steer = ((float*)c)[0];
|
||||
m_accel = ((float*)c)[1];
|
||||
setButtonsCompressed(c[8]);
|
||||
} // uncompress
|
||||
return m_steer == other.m_steer &&
|
||||
m_accel == other.m_accel &&
|
||||
m_brake == other.m_brake &&
|
||||
m_nitro == other.m_nitro &&
|
||||
m_skid == other.m_skid &&
|
||||
m_rescue == other.m_rescue &&
|
||||
m_fire == other.m_fire &&
|
||||
m_look_back == other.m_look_back;
|
||||
} // operator==
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Compresses all buttons into a single integer value. */
|
||||
/** Return the serialised size in bytes. */
|
||||
static int getLength() { return 9; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Copies the important data from this objects into a memory buffer. */
|
||||
void copyToBuffer(BareNetworkString *buffer) const
|
||||
{
|
||||
buffer->add(m_steer);
|
||||
buffer->add(m_accel);
|
||||
buffer->addChar(getButtonsCompressed());
|
||||
} // copyToBuffer
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Restores this object from a previously saved memory buffer. */
|
||||
void setFromBuffer(BareNetworkString *buffer)
|
||||
{
|
||||
m_steer = buffer->getFloat();
|
||||
m_accel = buffer->getFloat();
|
||||
setButtonsCompressed(buffer->getUInt8());
|
||||
} // setFromMemory
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Compresses all buttons into a single byte. */
|
||||
char getButtonsCompressed() const
|
||||
{
|
||||
return (m_brake ? 1 : 0)
|
||||
@ -82,7 +129,7 @@ public:
|
||||
+ (m_skid<<5); // m_skid is in {0,1,2,3}
|
||||
} // getButtonsCompressed
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets the buttons from a compressed representation.
|
||||
/** Sets the buttons from a compressed (1 byte) representation.
|
||||
* /param c Character containing the compressed representation.
|
||||
*/
|
||||
void setButtonsCompressed(char c)
|
||||
@ -94,6 +141,33 @@ public:
|
||||
m_look_back = (c & 16) != 0;
|
||||
m_skid = (SkidControl)((c & 96) >> 5);
|
||||
} // setButtonsCompressed
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the current steering value. */
|
||||
float getSteer() const { return m_steer; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns current acceleration. */
|
||||
float getAccel() const { return m_accel; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns if the kart is braking. */
|
||||
bool getBrake() const { return m_brake; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns if the kart activates nitro. */
|
||||
bool getNitro() const { return m_nitro; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the skidding control state: SC_NONE: not pressed;
|
||||
* SC_NO_DIRECTION: pressed, but no steering;
|
||||
* SC_LEFT/RIGHT: pressed in the specified direction. */
|
||||
SkidControl getSkidControl() const { return m_skid; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns true if the kart triggered rescue. */
|
||||
bool getRescue() const { return m_rescue; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns if fire is selected. */
|
||||
bool getFire() const { return m_fire; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns if the kart wants to look back (which also implies that it
|
||||
* will fire backwards. */
|
||||
bool getLookBack() const { return m_look_back; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -147,7 +147,8 @@ void LocalPlayerController::steer(float dt, int steer_val)
|
||||
|
||||
if(UserConfigParams::m_gamepad_debug)
|
||||
{
|
||||
Log::debug("LocalPlayerController", " set to: %f\n", m_controls->m_steer);
|
||||
Log::debug("LocalPlayerController", " set to: %f\n",
|
||||
m_controls->getSteer());
|
||||
}
|
||||
} // steer
|
||||
|
||||
@ -170,7 +171,7 @@ void LocalPlayerController::update(float dt)
|
||||
Camera *camera = Camera::getCamera(m_camera_index);
|
||||
if (camera->getType() != Camera::CM_TYPE_END)
|
||||
{
|
||||
if (m_controls->m_look_back || (UserConfigParams::m_reverse_look_threshold > 0 &&
|
||||
if (m_controls->getLookBack() || (UserConfigParams::m_reverse_look_threshold > 0 &&
|
||||
m_kart->getSpeed() < -UserConfigParams::m_reverse_look_threshold))
|
||||
{
|
||||
camera->setMode(Camera::CM_REVERSE);
|
||||
|
@ -102,8 +102,8 @@ void PlayerController::action(PlayerAction action, int value)
|
||||
if (value)
|
||||
{
|
||||
m_steer_val = value;
|
||||
if(m_controls->m_skid==KartControl::SC_NO_DIRECTION)
|
||||
m_controls->m_skid = KartControl::SC_LEFT;
|
||||
if(m_controls->getSkidControl()==KartControl::SC_NO_DIRECTION)
|
||||
m_controls->setSkidControl(KartControl::SC_LEFT);
|
||||
}
|
||||
else
|
||||
m_steer_val = m_steer_val_r;
|
||||
@ -114,8 +114,8 @@ void PlayerController::action(PlayerAction action, int value)
|
||||
if (value)
|
||||
{
|
||||
m_steer_val = -value;
|
||||
if(m_controls->m_skid==KartControl::SC_NO_DIRECTION)
|
||||
m_controls->m_skid = KartControl::SC_RIGHT;
|
||||
if(m_controls->getSkidControl()==KartControl::SC_NO_DIRECTION)
|
||||
m_controls->setSkidControl(KartControl::SC_RIGHT);
|
||||
}
|
||||
else
|
||||
m_steer_val = m_steer_val_l;
|
||||
@ -125,15 +125,15 @@ void PlayerController::action(PlayerAction action, int value)
|
||||
m_prev_accel = value;
|
||||
if (value && !(m_penalty_time > 0.0f))
|
||||
{
|
||||
m_controls->m_accel = value/32768.0f;
|
||||
m_controls->m_brake = false;
|
||||
m_controls->m_nitro = m_prev_nitro;
|
||||
m_controls->setAccel(value/32768.0f);
|
||||
m_controls->setBrake(false);
|
||||
m_controls->setNitro(m_prev_nitro);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_controls->m_accel = 0.0f;
|
||||
m_controls->m_brake = m_prev_brake;
|
||||
m_controls->m_nitro = false;
|
||||
m_controls->setAccel(0.0f);
|
||||
m_controls->setBrake(m_prev_brake);
|
||||
m_controls->setNitro(false);
|
||||
}
|
||||
break;
|
||||
case PA_BRAKE:
|
||||
@ -141,44 +141,44 @@ void PlayerController::action(PlayerAction action, int value)
|
||||
// let's consider below that to be a deadzone
|
||||
if(value > 32768/2)
|
||||
{
|
||||
m_controls->m_brake = true;
|
||||
m_controls->m_accel = 0.0f;
|
||||
m_controls->m_nitro = false;
|
||||
m_controls->setBrake(true);
|
||||
m_controls->setAccel(0.0f);
|
||||
m_controls->setNitro(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_controls->m_brake = false;
|
||||
m_controls->m_accel = m_prev_accel/32768.0f;
|
||||
m_controls->setBrake(false);
|
||||
m_controls->setAccel(m_prev_accel/32768.0f);
|
||||
// Nitro still depends on whether we're accelerating
|
||||
m_controls->m_nitro = (m_prev_nitro && m_prev_accel);
|
||||
m_controls->setNitro(m_prev_nitro && m_prev_accel);
|
||||
}
|
||||
break;
|
||||
case PA_NITRO:
|
||||
// This basically keeps track whether the button still is being pressed
|
||||
m_prev_nitro = (value != 0);
|
||||
// Enable nitro only when also accelerating
|
||||
m_controls->m_nitro = ((value!=0) && m_controls->m_accel);
|
||||
m_controls->setNitro( ((value!=0) && m_controls->getAccel()) );
|
||||
break;
|
||||
case PA_RESCUE:
|
||||
m_controls->m_rescue = (value!=0);
|
||||
m_controls->setRescue(value!=0);
|
||||
break;
|
||||
case PA_FIRE:
|
||||
m_controls->m_fire = (value!=0);
|
||||
m_controls->setFire(value!=0);
|
||||
break;
|
||||
case PA_LOOK_BACK:
|
||||
m_controls->m_look_back = (value!=0);
|
||||
m_controls->setLookBack(value!=0);
|
||||
break;
|
||||
case PA_DRIFT:
|
||||
if(value==0)
|
||||
m_controls->m_skid = KartControl::SC_NONE;
|
||||
m_controls->setSkidControl(KartControl::SC_NONE);
|
||||
else
|
||||
{
|
||||
if(m_steer_val==0)
|
||||
m_controls->m_skid = KartControl::SC_NO_DIRECTION;
|
||||
m_controls->setSkidControl(KartControl::SC_NO_DIRECTION);
|
||||
else
|
||||
m_controls->m_skid = m_steer_val<0
|
||||
? KartControl::SC_RIGHT
|
||||
: KartControl::SC_LEFT;
|
||||
m_controls->setSkidControl(m_steer_val<0
|
||||
? KartControl::SC_RIGHT
|
||||
: KartControl::SC_LEFT );
|
||||
}
|
||||
break;
|
||||
case PA_PAUSE_RACE:
|
||||
@ -195,52 +195,54 @@ void PlayerController::action(PlayerAction action, int value)
|
||||
*/
|
||||
void PlayerController::steer(float dt, int steer_val)
|
||||
{
|
||||
// Get the old value, compute the new steering value,
|
||||
// and set it at the end of this function
|
||||
float steer = m_controls->getSteer();
|
||||
if(stk_config->m_disable_steer_while_unskid &&
|
||||
m_controls->m_skid==KartControl::SC_NONE &&
|
||||
m_controls->getSkidControl()==KartControl::SC_NONE &&
|
||||
m_kart->getSkidding()->getVisualSkidRotation()!=0)
|
||||
{
|
||||
m_controls->m_steer = 0;
|
||||
steer = 0;
|
||||
}
|
||||
|
||||
|
||||
// Amount the steering is changed for digital devices.
|
||||
// If the steering is 'back to straight', a different steering
|
||||
// change speed is used.
|
||||
const float STEER_CHANGE = ( (steer_val<=0 && m_controls->m_steer<0) ||
|
||||
(steer_val>=0 && m_controls->m_steer>0) )
|
||||
const float STEER_CHANGE = ( (steer_val<=0 && steer<0) ||
|
||||
(steer_val>=0 && steer>0) )
|
||||
? dt/m_kart->getKartProperties()->getTurnTimeResetSteer()
|
||||
: dt/m_kart->getTimeFullSteer(fabsf(m_controls->m_steer));
|
||||
: dt/m_kart->getTimeFullSteer(fabsf(steer));
|
||||
if (steer_val < 0)
|
||||
{
|
||||
// If we got analog values do not cumulate.
|
||||
if (steer_val > -32767)
|
||||
m_controls->m_steer = -steer_val/32767.0f;
|
||||
steer = -steer_val/32767.0f;
|
||||
else
|
||||
m_controls->m_steer += STEER_CHANGE;
|
||||
steer += STEER_CHANGE;
|
||||
}
|
||||
else if(steer_val > 0)
|
||||
{
|
||||
// If we got analog values do not cumulate.
|
||||
if (steer_val < 32767)
|
||||
m_controls->m_steer = -steer_val/32767.0f;
|
||||
steer = -steer_val/32767.0f;
|
||||
else
|
||||
m_controls->m_steer -= STEER_CHANGE;
|
||||
steer -= STEER_CHANGE;
|
||||
}
|
||||
else
|
||||
{ // no key is pressed
|
||||
if(m_controls->m_steer>0.0f)
|
||||
if(steer>0.0f)
|
||||
{
|
||||
m_controls->m_steer -= STEER_CHANGE;
|
||||
if(m_controls->m_steer<0.0f) m_controls->m_steer=0.0f;
|
||||
steer -= STEER_CHANGE;
|
||||
if(steer<0.0f) steer=0.0f;
|
||||
}
|
||||
else
|
||||
{ // m_controls->m_steer<=0.0f;
|
||||
m_controls->m_steer += STEER_CHANGE;
|
||||
if(m_controls->m_steer>0.0f) m_controls->m_steer=0.0f;
|
||||
} // if m_controls->m_steer<=0.0f
|
||||
{ // steer<=0.0f;
|
||||
steer += STEER_CHANGE;
|
||||
if(steer>0.0f) steer=0.0f;
|
||||
} // if steer<=0.0f
|
||||
} // no key is pressed
|
||||
|
||||
m_controls->m_steer = std::min(1.0f, std::max(-1.0f, m_controls->m_steer));
|
||||
m_controls->setSteer(std::min(1.0f, std::max(-1.0f, steer)) );
|
||||
|
||||
} // steer
|
||||
|
||||
@ -250,7 +252,7 @@ void PlayerController::steer(float dt, int steer_val)
|
||||
*/
|
||||
void PlayerController::skidBonusTriggered()
|
||||
{
|
||||
m_controls->m_steer = 0;
|
||||
m_controls->setSteer(0);
|
||||
} // skidBonusTriggered
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -266,15 +268,15 @@ void PlayerController::update(float dt)
|
||||
|
||||
if (World::getWorld()->getPhase() == World::GOAL_PHASE)
|
||||
{
|
||||
m_controls->m_brake = false;
|
||||
m_controls->m_accel = 0.0f;
|
||||
m_controls->setBrake(false);
|
||||
m_controls->setAccel(0.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
if (World::getWorld()->isStartPhase())
|
||||
{
|
||||
if (m_controls->m_accel || m_controls->m_brake ||
|
||||
m_controls->m_fire || m_controls->m_nitro)
|
||||
if (m_controls->getAccel() || m_controls->getBrake()||
|
||||
m_controls->getFire() || m_controls->getNitro())
|
||||
{
|
||||
// Only give penalty time in SET_PHASE.
|
||||
// Penalty time check makes sure it doesn't get rendered on every
|
||||
@ -286,8 +288,8 @@ void PlayerController::update(float dt)
|
||||
m_penalty_time = stk_config->m_penalty_time;
|
||||
} // if penalty_time = 0
|
||||
|
||||
m_controls->m_brake = false;
|
||||
m_controls->m_accel = 0.0f;
|
||||
m_controls->setBrake(false);
|
||||
m_controls->setAccel(0.0f);
|
||||
} // if key pressed
|
||||
|
||||
return;
|
||||
@ -302,10 +304,10 @@ void PlayerController::update(float dt)
|
||||
// Only accept rescue if there is no kart animation is already playing
|
||||
// (e.g. if an explosion happens, wait till the explosion is over before
|
||||
// starting any other animation).
|
||||
if ( m_controls->m_rescue && !m_kart->getKartAnimation() )
|
||||
if ( m_controls->getRescue() && !m_kart->getKartAnimation() )
|
||||
{
|
||||
new RescueAnimation(m_kart);
|
||||
m_controls->m_rescue=false;
|
||||
m_controls->setRescue(false);
|
||||
}
|
||||
} // update
|
||||
|
||||
|
@ -223,8 +223,8 @@ unsigned int SkiddingAI::getNextSector(unsigned int index)
|
||||
void SkiddingAI::update(float dt)
|
||||
{
|
||||
// This is used to enable firing an item backwards.
|
||||
m_controls->m_look_back = false;
|
||||
m_controls->m_nitro = false;
|
||||
m_controls->setLookBack(false);
|
||||
m_controls->setNitro(false);
|
||||
|
||||
// Don't do anything if there is currently a kart animations shown.
|
||||
if(m_kart->getKartAnimation())
|
||||
@ -286,8 +286,8 @@ void SkiddingAI::update(float dt)
|
||||
// or slipstreaming.
|
||||
#undef AI_DOES_NOT_MOVE_FOR_DEBUGGING
|
||||
#ifdef AI_DOES_NOT_MOVE_FOR_DEBUGGING
|
||||
m_controls->m_accel = 0;
|
||||
m_controls->m_steer = 0;
|
||||
m_controls->setAccel(0);
|
||||
m_controls->setSteer(0);
|
||||
return;
|
||||
#endif
|
||||
|
||||
@ -324,8 +324,8 @@ void SkiddingAI::update(float dt)
|
||||
m_kart_ahead )
|
||||
{
|
||||
// Use nitro if the kart is far ahead, or faster than this kart
|
||||
m_controls->m_nitro = m_distance_ahead>10.0f ||
|
||||
m_kart_ahead->getSpeed() > m_kart->getSpeed();
|
||||
m_controls->setNitro(m_distance_ahead>10.0f ||
|
||||
m_kart_ahead->getSpeed() > m_kart->getSpeed());
|
||||
// If we are close enough, try to hit this kart
|
||||
if(m_distance_ahead<=10)
|
||||
{
|
||||
@ -355,12 +355,12 @@ void SkiddingAI::update(float dt)
|
||||
handleRescue(dt);
|
||||
handleBraking();
|
||||
// If a bomb is attached, nitro might already be set.
|
||||
if(!m_controls->m_nitro)
|
||||
if(!m_controls->getNitro())
|
||||
handleNitroAndZipper();
|
||||
}
|
||||
// If we are supposed to use nitro, but have a zipper,
|
||||
// use the zipper instead (unless there are items to avoid cloe by)
|
||||
if(m_controls->m_nitro &&
|
||||
if(m_controls->getNitro() &&
|
||||
m_kart->getPowerup()->getType()==PowerupManager::POWERUP_ZIPPER &&
|
||||
m_kart->getSpeed()>1.0f &&
|
||||
m_kart->getSpeedIncreaseTimeLeft(MaxSpeed::MS_INCREASE_ZIPPER)<=0 &&
|
||||
@ -372,8 +372,8 @@ void SkiddingAI::update(float dt)
|
||||
if(race_manager->getMinorMode()!=RaceManager::MINOR_MODE_TIME_TRIAL ||
|
||||
(m_world->getTime()<3.0f && rand()%50==1) )
|
||||
{
|
||||
m_controls->m_nitro = false;
|
||||
m_controls->m_fire = true;
|
||||
m_controls->setNitro(false);
|
||||
m_controls->setFire(true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -391,7 +391,7 @@ void SkiddingAI::update(float dt)
|
||||
*/
|
||||
void SkiddingAI::handleBraking()
|
||||
{
|
||||
m_controls->m_brake = false;
|
||||
m_controls->setBrake(false);
|
||||
// In follow the leader mode, the kart should brake if they are ahead of
|
||||
// the leader (and not the leader, i.e. don't have initial position 1)
|
||||
if(race_manager->getMinorMode() == RaceManager::MINOR_MODE_FOLLOW_LEADER &&
|
||||
@ -404,7 +404,7 @@ void SkiddingAI::handleBraking()
|
||||
m_kart->getIdent().c_str());
|
||||
#endif
|
||||
|
||||
m_controls->m_brake = true;
|
||||
m_controls->setBrake(true);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -424,7 +424,7 @@ void SkiddingAI::handleBraking()
|
||||
"%s not aligned with track.",
|
||||
m_kart->getIdent().c_str());
|
||||
#endif
|
||||
m_controls->m_brake = true;
|
||||
m_controls->setBrake(true);
|
||||
return;
|
||||
}
|
||||
if(m_current_track_direction==DriveNode::DIR_LEFT ||
|
||||
@ -435,9 +435,9 @@ void SkiddingAI::handleBraking()
|
||||
|
||||
if(m_kart->getSpeed() > 1.5f*max_turn_speed &&
|
||||
m_kart->getSpeed()>MIN_SPEED &&
|
||||
fabsf(m_controls->m_steer) > 0.95f )
|
||||
fabsf(m_controls->getSteer()) > 0.95f )
|
||||
{
|
||||
m_controls->m_brake = true;
|
||||
m_controls->setBrake(true);
|
||||
#ifdef DEBUG
|
||||
if(m_ai_debug)
|
||||
Log::debug(getControllerName().c_str(),
|
||||
@ -1144,7 +1144,7 @@ void SkiddingAI::evaluateItems(const Item *item, Vec3 kart_aim_direction,
|
||||
*/
|
||||
void SkiddingAI::handleItems(const float dt)
|
||||
{
|
||||
m_controls->m_fire = false;
|
||||
m_controls->setFire(false);
|
||||
if(m_kart->getKartAnimation() ||
|
||||
m_kart->getPowerup()->getType() == PowerupManager::POWERUP_NOTHING )
|
||||
return;
|
||||
@ -1153,12 +1153,12 @@ void SkiddingAI::handleItems(const float dt)
|
||||
|
||||
if (m_superpower == RaceManager::SUPERPOWER_NOLOK_BOSS)
|
||||
{
|
||||
m_controls->m_look_back = (m_kart->getPowerup()->getType() ==
|
||||
PowerupManager::POWERUP_BOWLING );
|
||||
m_controls->setLookBack(m_kart->getPowerup()->getType() ==
|
||||
PowerupManager::POWERUP_BOWLING );
|
||||
|
||||
if( m_time_since_last_shot > 3.0f )
|
||||
{
|
||||
m_controls->m_fire = true;
|
||||
m_controls->setFire(true);
|
||||
if (m_kart->getPowerup()->getType() == PowerupManager::POWERUP_SWATTER)
|
||||
m_time_since_last_shot = 3.0f;
|
||||
else
|
||||
@ -1169,7 +1169,7 @@ void SkiddingAI::handleItems(const float dt)
|
||||
}
|
||||
else
|
||||
{
|
||||
m_controls->m_fire = false;
|
||||
m_controls->setFire(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -1180,7 +1180,7 @@ void SkiddingAI::handleItems(const float dt)
|
||||
{
|
||||
if( m_time_since_last_shot > 10.0f )
|
||||
{
|
||||
m_controls->m_fire = true;
|
||||
m_controls->setFire(true);
|
||||
m_time_since_last_shot = 0.0f;
|
||||
}
|
||||
return;
|
||||
@ -1196,8 +1196,7 @@ void SkiddingAI::handleItems(const float dt)
|
||||
{
|
||||
Attachment::AttachmentType type = m_kart->getAttachment()->getType();
|
||||
// Don't use shield when we have a swatter.
|
||||
if( type == Attachment::ATTACH_SWATTER ||
|
||||
type == Attachment::ATTACH_NOLOKS_SWATTER )
|
||||
if( type == Attachment::ATTACH_SWATTER)
|
||||
break;
|
||||
|
||||
// Check if a flyable (cake, ...) is close. If so, use bubblegum
|
||||
@ -1206,8 +1205,8 @@ void SkiddingAI::handleItems(const float dt)
|
||||
projectile_manager->projectileIsClose(m_kart,
|
||||
m_ai_properties->m_shield_incoming_radius) )
|
||||
{
|
||||
m_controls->m_fire = true;
|
||||
m_controls->m_look_back = false;
|
||||
m_controls->setFire(true);
|
||||
m_controls->setLookBack(false);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1222,8 +1221,8 @@ void SkiddingAI::handleItems(const float dt)
|
||||
// overtaken kart to overtake us again.
|
||||
if(m_distance_behind < 15.0f && m_distance_behind > 3.0f )
|
||||
{
|
||||
m_controls->m_fire = true;
|
||||
m_controls->m_look_back = true;
|
||||
m_controls->setFire(true);
|
||||
m_controls->setLookBack(true);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1235,8 +1234,8 @@ void SkiddingAI::handleItems(const float dt)
|
||||
lin_world->getKartLaps(m_kart->getWorldKartId())
|
||||
== race_manager->getNumLaps()-1)
|
||||
{
|
||||
m_controls->m_fire = true;
|
||||
m_controls->m_look_back = true;
|
||||
m_controls->setFire(true);
|
||||
m_controls->setLookBack(true);
|
||||
break;
|
||||
}
|
||||
break; // POWERUP_BUBBLEGUM
|
||||
@ -1282,10 +1281,10 @@ void SkiddingAI::handleItems(const float dt)
|
||||
: m_distance_ahead;
|
||||
// Since cakes can be fired all around, just use a sane distance
|
||||
// with a bit of extra for backwards, as enemy will go towards cake
|
||||
m_controls->m_fire = (fire_backwards && distance < 25.0f) ||
|
||||
(!fire_backwards && distance < 20.0f);
|
||||
if(m_controls->m_fire)
|
||||
m_controls->m_look_back = fire_backwards;
|
||||
m_controls->setFire( (fire_backwards && distance < 25.0f) ||
|
||||
(!fire_backwards && distance < 20.0f) );
|
||||
if(m_controls->getFire())
|
||||
m_controls->setLookBack(fire_backwards);
|
||||
break;
|
||||
} // POWERUP_CAKE
|
||||
|
||||
@ -1332,12 +1331,12 @@ void SkiddingAI::handleItems(const float dt)
|
||||
|
||||
float distance = fire_backwards ? m_distance_behind
|
||||
: m_distance_ahead;
|
||||
m_controls->m_fire = ( (fire_backwards && distance < 30.0f) ||
|
||||
m_controls->setFire( ( (fire_backwards && distance < 30.0f) ||
|
||||
(!fire_backwards && distance <10.0f) ) &&
|
||||
m_time_since_last_shot > 3.0f &&
|
||||
(straight_behind || straight_ahead);
|
||||
if(m_controls->m_fire)
|
||||
m_controls->m_look_back = fire_backwards;
|
||||
(straight_behind || straight_ahead) );
|
||||
if(m_controls->getFire())
|
||||
m_controls->setLookBack(fire_backwards);
|
||||
break;
|
||||
} // POWERUP_BOWLING
|
||||
|
||||
@ -1363,10 +1362,10 @@ void SkiddingAI::handleItems(const float dt)
|
||||
!m_kart_ahead;
|
||||
float distance = fire_backwards ? m_distance_behind
|
||||
: m_distance_ahead;
|
||||
m_controls->m_fire = distance < 30.0f ||
|
||||
m_time_since_last_shot > 10.0f;
|
||||
if(m_controls->m_fire)
|
||||
m_controls->m_look_back = fire_backwards;
|
||||
m_controls->setFire(distance < 30.0f ||
|
||||
m_time_since_last_shot > 10.0f );
|
||||
if(m_controls->getFire())
|
||||
m_controls->setLookBack(fire_backwards);
|
||||
break;
|
||||
} // POWERUP_PLUNGER
|
||||
|
||||
@ -1376,13 +1375,13 @@ void SkiddingAI::handleItems(const float dt)
|
||||
// after a waiting an appropriate time
|
||||
if(m_kart->getPosition()>1 &&
|
||||
m_time_since_last_shot > stk_config->m_item_switch_time+2.0f)
|
||||
m_controls->m_fire = true;
|
||||
m_controls->setFire(true);
|
||||
break; // POWERUP_SWITCH
|
||||
|
||||
case PowerupManager::POWERUP_PARACHUTE:
|
||||
// Wait one second more than a previous parachute
|
||||
if(m_time_since_last_shot > m_kart->getKartProperties()->getParachuteDurationOther() + 1.0f)
|
||||
m_controls->m_fire = true;
|
||||
m_controls->setFire(true);
|
||||
break; // POWERUP_PARACHUTE
|
||||
|
||||
case PowerupManager::POWERUP_ANVIL:
|
||||
@ -1391,13 +1390,13 @@ void SkiddingAI::handleItems(const float dt)
|
||||
|
||||
if(race_manager->getMinorMode()==RaceManager::MINOR_MODE_FOLLOW_LEADER)
|
||||
{
|
||||
m_controls->m_fire = m_world->getTime()<1.0f &&
|
||||
m_kart->getPosition()>2;
|
||||
m_controls->setFire(m_world->getTime()<1.0f &&
|
||||
m_kart->getPosition()>2 );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_controls->m_fire = m_time_since_last_shot > 3.0f &&
|
||||
m_kart->getPosition()>1;
|
||||
m_controls->setFire(m_time_since_last_shot > 3.0f &&
|
||||
m_kart->getPosition()>1 );
|
||||
}
|
||||
break; // POWERUP_ANVIL
|
||||
|
||||
@ -1418,7 +1417,7 @@ void SkiddingAI::handleItems(const float dt)
|
||||
m_kart_ahead->getSpeed() < m_kart->getSpeed() ) ||
|
||||
( m_kart_behind && !m_kart_behind->isSquashed() &&
|
||||
(m_kart_behind->getXYZ()-m_kart->getXYZ()).length2()<d2) )
|
||||
m_controls->m_fire = true;
|
||||
m_controls->setFire(true);
|
||||
break;
|
||||
}
|
||||
case PowerupManager::POWERUP_RUBBERBALL:
|
||||
@ -1428,7 +1427,7 @@ void SkiddingAI::handleItems(const float dt)
|
||||
// Perhaps some more sophisticated algorithm might be useful.
|
||||
// For now: fire if there is a kart ahead (which means that
|
||||
// this kart is certainly not the first kart)
|
||||
m_controls->m_fire = m_kart_ahead != NULL;
|
||||
m_controls->setFire(m_kart_ahead != NULL);
|
||||
break;
|
||||
default:
|
||||
Log::error(getControllerName().c_str(),
|
||||
@ -1436,7 +1435,7 @@ void SkiddingAI::handleItems(const float dt)
|
||||
m_kart->getPowerup()->getType());
|
||||
assert(false);
|
||||
}
|
||||
if(m_controls->m_fire) m_time_since_last_shot = 0.0f;
|
||||
if(m_controls->getFire()) m_time_since_last_shot = 0.0f;
|
||||
} // handleItems
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -1512,26 +1511,26 @@ void SkiddingAI::handleAcceleration( const float dt)
|
||||
if( m_start_delay > 0.0f )
|
||||
{
|
||||
m_start_delay -= dt;
|
||||
m_controls->m_accel = 0.0f;
|
||||
m_controls->setAccel(0.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
if( m_controls->m_brake )
|
||||
if( m_controls->getBrake())
|
||||
{
|
||||
m_controls->m_accel = 0.0f;
|
||||
m_controls->setAccel(0.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_kart->getBlockedByPlungerTime()>0)
|
||||
{
|
||||
if(m_kart->getSpeed() < m_kart->getCurrentMaxSpeed() / 2)
|
||||
m_controls->m_accel = 0.05f;
|
||||
m_controls->setAccel(0.05f);
|
||||
else
|
||||
m_controls->m_accel = 0.0f;
|
||||
m_controls->setAccel(0.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
m_controls->m_accel = stk_config->m_ai_acceleration;
|
||||
m_controls->setAccel(stk_config->m_ai_acceleration);
|
||||
|
||||
} // handleAcceleration
|
||||
|
||||
@ -1588,7 +1587,7 @@ void SkiddingAI::handleRescue(const float dt)
|
||||
*/
|
||||
void SkiddingAI::handleNitroAndZipper()
|
||||
{
|
||||
m_controls->m_nitro = false;
|
||||
m_controls->setNitro(false);
|
||||
// If we are already very fast, save nitro.
|
||||
if(m_kart->getSpeed() > 0.95f*m_kart->getCurrentMaxSpeed())
|
||||
return;
|
||||
@ -1596,7 +1595,7 @@ void SkiddingAI::handleNitroAndZipper()
|
||||
if(m_kart->getBlockedByPlungerTime()>0) return;
|
||||
|
||||
// Don't use nitro if we are braking
|
||||
if(m_controls->m_brake) return;
|
||||
if(m_controls->getBrake()) return;
|
||||
|
||||
// Don't use nitro if the kart is not on ground or has finished the race
|
||||
if(!m_kart->isOnGround() || m_kart->hasFinishedRace()) return;
|
||||
@ -1626,7 +1625,7 @@ void SkiddingAI::handleNitroAndZipper()
|
||||
// If the kart is very slow (e.g. after rescue), use nitro
|
||||
if(m_kart->getSpeed()<5)
|
||||
{
|
||||
m_controls->m_nitro = true;
|
||||
m_controls->setNitro(true);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1637,7 +1636,7 @@ void SkiddingAI::handleNitroAndZipper()
|
||||
if(m_kart->getPosition()== (int)num_karts &&
|
||||
num_karts>1 && m_kart->getEnergy()>2.0f)
|
||||
{
|
||||
m_controls->m_nitro = true;
|
||||
m_controls->setNitro(true);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1653,7 +1652,7 @@ void SkiddingAI::handleNitroAndZipper()
|
||||
m_world->getEstimatedFinishTime(m_kart->getWorldKartId());
|
||||
if( 1.5f*m_kart->getEnergy() >= finish - m_world->getTime() )
|
||||
{
|
||||
m_controls->m_nitro = true;
|
||||
m_controls->setNitro(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -1669,7 +1668,7 @@ void SkiddingAI::handleNitroAndZipper()
|
||||
m_distance_ahead < overtake_distance &&
|
||||
m_kart_ahead->getSpeed()+5.0f > m_kart->getSpeed() )
|
||||
{
|
||||
m_controls->m_nitro = true;
|
||||
m_controls->setNitro(true);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1678,8 +1677,8 @@ void SkiddingAI::handleNitroAndZipper()
|
||||
m_kart_behind->getSpeed() > m_kart->getSpeed() )
|
||||
{
|
||||
// Only prevent overtaking on highest level
|
||||
m_controls->m_nitro = m_ai_properties->m_nitro_usage
|
||||
== AIProperties::NITRO_ALL;
|
||||
m_controls->setNitro(m_ai_properties->m_nitro_usage
|
||||
== AIProperties::NITRO_ALL);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1697,7 +1696,7 @@ void SkiddingAI::handleNitroAndZipper()
|
||||
- DriveGraph::get()->getDistanceFromStart(m_track_node);
|
||||
if(diff<0) diff+=World::getWorld()->getTrack()->getTrackLength();
|
||||
if(diff>m_ai_properties->m_straight_length_for_zipper)
|
||||
m_controls->m_fire = true;
|
||||
m_controls->setFire(true);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1934,7 +1933,6 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node)
|
||||
m_curve[CURVE_KART]->addPoint(m_kart->getTrans()(forw)+eps);
|
||||
#endif
|
||||
*last_node = m_next_node_index[m_track_node];
|
||||
int target_sector;
|
||||
|
||||
Vec3 direction;
|
||||
Vec3 step_track_coord;
|
||||
@ -1946,7 +1944,7 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node)
|
||||
{
|
||||
// target_sector is the sector at the longest distance that we can
|
||||
// drive to without crashing with the track.
|
||||
target_sector = m_next_node_index[*last_node];
|
||||
int target_sector = m_next_node_index[*last_node];
|
||||
|
||||
//direction is a vector from our kart to the sectors we are testing
|
||||
direction = DriveGraph::get()->getNode(target_sector)->getCenter()
|
||||
@ -2030,12 +2028,10 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node)
|
||||
*last_node = m_next_node_index[m_track_node];
|
||||
float angle = DriveGraph::get()->getAngleToNext(m_track_node,
|
||||
m_successor_index[m_track_node]);
|
||||
int target_sector;
|
||||
|
||||
Vec3 direction;
|
||||
Vec3 step_track_coord;
|
||||
|
||||
float angle1;
|
||||
// The original while(1) loop is replaced with a for loop to avoid
|
||||
// infinite loops (which we had once or twice). Usually the number
|
||||
// of iterations in the while loop is less than 7.
|
||||
@ -2043,8 +2039,8 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node)
|
||||
{
|
||||
// target_sector is the sector at the longest distance that we can
|
||||
// drive to without crashing with the track.
|
||||
target_sector = m_next_node_index[*last_node];
|
||||
angle1 = DriveGraph::get()->getAngleToNext(target_sector,
|
||||
int target_sector = m_next_node_index[*last_node];
|
||||
float angle1 = DriveGraph::get()->getAngleToNext(target_sector,
|
||||
m_successor_index[target_sector]);
|
||||
// In very sharp turns this algorithm tends to aim at off track points,
|
||||
// resulting in hitting a corner. So test for this special case and
|
||||
@ -2231,7 +2227,7 @@ bool SkiddingAI::canSkid(float steer_fraction)
|
||||
// If the kart has to do a sharp turn, but is already skidding, find
|
||||
// a good time to release the skid button, since this will turn the
|
||||
// kart more sharply:
|
||||
if(m_controls->m_skid)
|
||||
if(m_controls->getSkidControl())
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if(m_ai_debug)
|
||||
@ -2256,7 +2252,7 @@ bool SkiddingAI::canSkid(float steer_fraction)
|
||||
m_current_track_direction==DriveNode::DIR_UNDEFINED )
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if(m_controls->m_skid && m_ai_debug)
|
||||
if(m_controls->getSkidControl() && m_ai_debug)
|
||||
{
|
||||
Log::debug(getControllerName().c_str(),
|
||||
"%s stops skidding on straight.",
|
||||
@ -2293,7 +2289,7 @@ bool SkiddingAI::canSkid(float steer_fraction)
|
||||
|
||||
// If the remaining estimated time for skidding is too short, stop
|
||||
// it. This code will mostly trigger the bonus at the end of a skid.
|
||||
if(m_controls->m_skid && duration < 1.0f)
|
||||
if(m_controls->getSkidControl() && duration < 1.0f)
|
||||
{
|
||||
if(m_ai_debug)
|
||||
Log::debug(getControllerName().c_str(),
|
||||
@ -2311,7 +2307,7 @@ bool SkiddingAI::canSkid(float steer_fraction)
|
||||
m_current_track_direction==DriveNode::DIR_RIGHT) )
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if(m_controls->m_skid && m_ai_debug)
|
||||
if(m_controls->getSkidControl() && m_ai_debug)
|
||||
Log::debug(getControllerName().c_str(),
|
||||
"%s skidding against track direction.",
|
||||
m_kart->getIdent().c_str());
|
||||
@ -2323,7 +2319,7 @@ bool SkiddingAI::canSkid(float steer_fraction)
|
||||
m_kart->getKartProperties()->getSkidTimeTillBonus()[0] < duration)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if(!m_controls->m_skid && m_ai_debug)
|
||||
if(!m_controls->getSkidControl() && m_ai_debug)
|
||||
Log::debug(getControllerName().c_str(),
|
||||
"%s start skid, duration %f.",
|
||||
m_kart->getIdent().c_str(), duration);
|
||||
@ -2333,7 +2329,7 @@ bool SkiddingAI::canSkid(float steer_fraction)
|
||||
} // if curve long enough for skidding
|
||||
|
||||
#ifdef DEBUG
|
||||
if(m_controls->m_skid && m_ai_debug)
|
||||
if(m_controls->getSkidControl() && m_ai_debug)
|
||||
Log::debug(getControllerName().c_str(),
|
||||
"%s has no reasons to skid anymore.",
|
||||
m_kart->getIdent().c_str());
|
||||
@ -2364,7 +2360,7 @@ void SkiddingAI::setSteering(float angle, float dt)
|
||||
if(!canSkid(steer_fraction))
|
||||
{
|
||||
m_skid_probability_state = SKID_PROBAB_NOT_YET;
|
||||
m_controls->m_skid = KartControl::SC_NONE;
|
||||
m_controls->setSkidControl(KartControl::SC_NONE);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2387,8 +2383,8 @@ void SkiddingAI::setSteering(float angle, float dt)
|
||||
sc= ? "no" : sc==KartControl::SC_LEFT ? "left" : "right");
|
||||
#endif
|
||||
}
|
||||
m_controls->m_skid = m_skid_probability_state == SKID_PROBAB_SKID
|
||||
? sc : KartControl::SC_NONE;
|
||||
m_controls->setSkidControl(m_skid_probability_state == SKID_PROBAB_SKID
|
||||
? sc : KartControl::SC_NONE );
|
||||
}
|
||||
|
||||
// Adjust steer fraction in case to be in [-1,1]
|
||||
@ -2412,7 +2408,7 @@ void SkiddingAI::setSteering(float angle, float dt)
|
||||
if((ss==Skidding::SKID_ACCUMULATE_LEFT && steer_fraction>0.2f ) ||
|
||||
(ss==Skidding::SKID_ACCUMULATE_RIGHT && steer_fraction<-0.2f) )
|
||||
{
|
||||
m_controls->m_skid = KartControl::SC_NONE;
|
||||
m_controls->setSkidControl(KartControl::SC_NONE);
|
||||
#ifdef DEBUG
|
||||
if(m_ai_debug)
|
||||
Log::info(getControllerName().c_str(),
|
||||
@ -2421,7 +2417,7 @@ void SkiddingAI::setSteering(float angle, float dt)
|
||||
#endif
|
||||
}
|
||||
|
||||
if(m_controls->m_skid!=KartControl::SC_NONE &&
|
||||
if(m_controls->getSkidControl()!=KartControl::SC_NONE &&
|
||||
( ss==Skidding::SKID_ACCUMULATE_LEFT ||
|
||||
ss==Skidding::SKID_ACCUMULATE_RIGHT ) )
|
||||
{
|
||||
@ -2435,7 +2431,7 @@ void SkiddingAI::setSteering(float angle, float dt)
|
||||
"%s steering too much (%f).",
|
||||
m_kart->getIdent().c_str(), steer_fraction);
|
||||
#endif
|
||||
m_controls->m_skid = KartControl::SC_NONE;
|
||||
m_controls->setSkidControl(KartControl::SC_NONE);
|
||||
}
|
||||
if(steer_fraction<-1.0f)
|
||||
steer_fraction = -1.0f;
|
||||
@ -2443,19 +2439,19 @@ void SkiddingAI::setSteering(float angle, float dt)
|
||||
steer_fraction = 1.0f;
|
||||
}
|
||||
|
||||
float old_steer = m_controls->m_steer;
|
||||
float old_steer = m_controls->getSteer();
|
||||
|
||||
// The AI has its own 'time full steer' value (which is the time
|
||||
float max_steer_change = dt/m_ai_properties->m_time_full_steer;
|
||||
if(old_steer < steer_fraction)
|
||||
{
|
||||
m_controls->m_steer = (old_steer+max_steer_change > steer_fraction)
|
||||
? steer_fraction : old_steer+max_steer_change;
|
||||
m_controls->setSteer( (old_steer+max_steer_change > steer_fraction)
|
||||
? steer_fraction : old_steer+max_steer_change );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_controls->m_steer = (old_steer-max_steer_change < steer_fraction)
|
||||
? steer_fraction : old_steer-max_steer_change;
|
||||
m_controls->setSteer( (old_steer-max_steer_change < steer_fraction)
|
||||
? steer_fraction : old_steer-max_steer_change );
|
||||
}
|
||||
|
||||
|
||||
|
@ -119,8 +119,8 @@ void SoccerAI::update(float dt)
|
||||
if (m_world->getPhase() == World::GOAL_PHASE)
|
||||
{
|
||||
resetAfterStop();
|
||||
m_controls->m_brake = false;
|
||||
m_controls->m_accel = 0.0f;
|
||||
m_controls->setBrake(false);
|
||||
m_controls->setAccel(0.0f);
|
||||
AIBaseController::update(dt);
|
||||
return;
|
||||
}
|
||||
|
@ -229,8 +229,8 @@ unsigned int SkiddingAI::getNextSector(unsigned int index)
|
||||
void SkiddingAI::update(float dt)
|
||||
{
|
||||
// This is used to enable firing an item backwards.
|
||||
m_controls->m_look_back = false;
|
||||
m_controls->m_nitro = false;
|
||||
m_controls->setLookBack(false);
|
||||
m_controls->setNitro(false);
|
||||
|
||||
// Don't do anything if there is currently a kart animations shown.
|
||||
if(m_kart->getKartAnimation())
|
||||
@ -292,8 +292,8 @@ void SkiddingAI::update(float dt)
|
||||
// or slipstreaming.
|
||||
#undef AI_DOES_NOT_MOVE_FOR_DEBUGGING
|
||||
#ifdef AI_DOES_NOT_MOVE_FOR_DEBUGGING
|
||||
m_controls->m_accel = 0;
|
||||
m_controls->m_steer = 0;
|
||||
m_controls->setAccel(0);
|
||||
m_controls->setSteer(0);
|
||||
return;
|
||||
#endif
|
||||
|
||||
@ -330,8 +330,8 @@ void SkiddingAI::update(float dt)
|
||||
m_kart_ahead )
|
||||
{
|
||||
// Use nitro if the kart is far ahead, or faster than this kart
|
||||
m_controls->m_nitro = m_distance_ahead>10.0f ||
|
||||
m_kart_ahead->getSpeed() > m_kart->getSpeed();
|
||||
m_controls->setNitro(m_distance_ahead>10.0f ||
|
||||
m_kart_ahead->getSpeed() > m_kart->getSpeed());
|
||||
// If we are close enough, try to hit this kart
|
||||
if(m_distance_ahead<=10)
|
||||
{
|
||||
@ -361,12 +361,12 @@ void SkiddingAI::update(float dt)
|
||||
handleRescue(dt);
|
||||
handleBraking();
|
||||
// If a bomb is attached, nitro might already be set.
|
||||
if(!m_controls->m_nitro)
|
||||
if(!m_controls->getNitro())
|
||||
handleNitroAndZipper();
|
||||
}
|
||||
// If we are supposed to use nitro, but have a zipper,
|
||||
// use the zipper instead (unless there are items to avoid cloe by)
|
||||
if(m_controls->m_nitro &&
|
||||
if(m_controls->getNitro() &&
|
||||
m_kart->getPowerup()->getType()==PowerupManager::POWERUP_ZIPPER &&
|
||||
m_kart->getSpeed()>1.0f &&
|
||||
m_kart->getSpeedIncreaseTimeLeft(MaxSpeed::MS_INCREASE_ZIPPER)<=0 &&
|
||||
@ -378,8 +378,8 @@ void SkiddingAI::update(float dt)
|
||||
if(race_manager->getMinorMode()!=RaceManager::MINOR_MODE_TIME_TRIAL ||
|
||||
(m_world->getTime()<3.0f && rand()%50==1) )
|
||||
{
|
||||
m_controls->m_nitro = false;
|
||||
m_controls->m_fire = true;
|
||||
m_controls->setNitro(false);
|
||||
m_controls->setFire(true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -397,7 +397,7 @@ void SkiddingAI::update(float dt)
|
||||
*/
|
||||
void SkiddingAI::handleBraking()
|
||||
{
|
||||
m_controls->m_brake = false;
|
||||
m_controls->setBrake(false);
|
||||
// In follow the leader mode, the kart should brake if they are ahead of
|
||||
// the leader (and not the leader, i.e. don't have initial position 1)
|
||||
if(race_manager->getMinorMode() == RaceManager::MINOR_MODE_FOLLOW_LEADER &&
|
||||
@ -410,7 +410,7 @@ void SkiddingAI::handleBraking()
|
||||
m_kart->getIdent().c_str());
|
||||
#endif
|
||||
|
||||
m_controls->m_brake = true;
|
||||
m_controls->setBrake(true);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -430,7 +430,7 @@ void SkiddingAI::handleBraking()
|
||||
"%s not aligned with track.",
|
||||
m_kart->getIdent().c_str());
|
||||
#endif
|
||||
m_controls->m_brake = true;
|
||||
m_controls->setBrake(true);
|
||||
return;
|
||||
}
|
||||
if(m_current_track_direction==DriveNode::DIR_LEFT ||
|
||||
@ -441,9 +441,9 @@ void SkiddingAI::handleBraking()
|
||||
|
||||
if(m_kart->getSpeed() > 1.5f*max_turn_speed &&
|
||||
m_kart->getSpeed()>MIN_SPEED &&
|
||||
fabsf(m_controls->m_steer) > 0.95f )
|
||||
fabsf(m_controls->getSteer()) > 0.95f )
|
||||
{
|
||||
m_controls->m_brake = true;
|
||||
m_controls->setBrake(true);
|
||||
#ifdef DEBUG
|
||||
if(m_ai_debug)
|
||||
Log::debug(getControllerName().c_str(),
|
||||
@ -1150,7 +1150,7 @@ void SkiddingAI::evaluateItems(const Item *item, Vec3 kart_aim_direction,
|
||||
*/
|
||||
void SkiddingAI::handleItems(const float dt)
|
||||
{
|
||||
m_controls->m_fire = false;
|
||||
m_controls->setFire(false);
|
||||
if(m_kart->getKartAnimation() ||
|
||||
m_kart->getPowerup()->getType() == PowerupManager::POWERUP_NOTHING )
|
||||
return;
|
||||
@ -1159,12 +1159,12 @@ void SkiddingAI::handleItems(const float dt)
|
||||
|
||||
if (m_superpower == RaceManager::SUPERPOWER_NOLOK_BOSS)
|
||||
{
|
||||
m_controls->m_look_back = (m_kart->getPowerup()->getType() ==
|
||||
PowerupManager::POWERUP_BOWLING );
|
||||
m_controls->setLookBack(m_kart->getPowerup()->getType() ==
|
||||
PowerupManager::POWERUP_BOWLING );
|
||||
|
||||
if( m_time_since_last_shot > 3.0f )
|
||||
{
|
||||
m_controls->m_fire = true;
|
||||
m_controls->setFire(true);
|
||||
if (m_kart->getPowerup()->getType() == PowerupManager::POWERUP_SWATTER)
|
||||
m_time_since_last_shot = 3.0f;
|
||||
else
|
||||
@ -1175,7 +1175,7 @@ void SkiddingAI::handleItems(const float dt)
|
||||
}
|
||||
else
|
||||
{
|
||||
m_controls->m_fire = false;
|
||||
m_controls->setFire(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -1186,7 +1186,7 @@ void SkiddingAI::handleItems(const float dt)
|
||||
{
|
||||
if( m_time_since_last_shot > 10.0f )
|
||||
{
|
||||
m_controls->m_fire = true;
|
||||
m_controls->setFire(true);
|
||||
m_time_since_last_shot = 0.0f;
|
||||
}
|
||||
return;
|
||||
@ -1202,8 +1202,7 @@ void SkiddingAI::handleItems(const float dt)
|
||||
{
|
||||
Attachment::AttachmentType type = m_kart->getAttachment()->getType();
|
||||
// Don't use shield when we have a swatter.
|
||||
if( type == Attachment::ATTACH_SWATTER ||
|
||||
type == Attachment::ATTACH_NOLOKS_SWATTER )
|
||||
if( type == Attachment::ATTACH_SWATTER)
|
||||
break;
|
||||
|
||||
// Check if a flyable (cake, ...) is close. If so, use bubblegum
|
||||
@ -1212,8 +1211,8 @@ void SkiddingAI::handleItems(const float dt)
|
||||
projectile_manager->projectileIsClose(m_kart,
|
||||
m_ai_properties->m_shield_incoming_radius) )
|
||||
{
|
||||
m_controls->m_fire = true;
|
||||
m_controls->m_look_back = false;
|
||||
m_controls->setFire(true);
|
||||
m_controls->setLookBack(false);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1228,8 +1227,8 @@ void SkiddingAI::handleItems(const float dt)
|
||||
// overtaken kart to overtake us again.
|
||||
if(m_distance_behind < 15.0f && m_distance_behind > 3.0f )
|
||||
{
|
||||
m_controls->m_fire = true;
|
||||
m_controls->m_look_back = true;
|
||||
m_controls->setFire(true);
|
||||
m_controls->setLookBack(true);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1241,8 +1240,8 @@ void SkiddingAI::handleItems(const float dt)
|
||||
lin_world->getKartLaps(m_kart->getWorldKartId())
|
||||
== race_manager->getNumLaps()-1)
|
||||
{
|
||||
m_controls->m_fire = true;
|
||||
m_controls->m_look_back = true;
|
||||
m_controls->setFire(true);
|
||||
m_controls->setLookBack(true);
|
||||
break;
|
||||
}
|
||||
break; // POWERUP_BUBBLEGUM
|
||||
@ -1288,10 +1287,10 @@ void SkiddingAI::handleItems(const float dt)
|
||||
: m_distance_ahead;
|
||||
// Since cakes can be fired all around, just use a sane distance
|
||||
// with a bit of extra for backwards, as enemy will go towards cake
|
||||
m_controls->m_fire = (fire_backwards && distance < 25.0f) ||
|
||||
(!fire_backwards && distance < 20.0f);
|
||||
if(m_controls->m_fire)
|
||||
m_controls->m_look_back = fire_backwards;
|
||||
m_controls->setFire( (fire_backwards && distance < 25.0f) ||
|
||||
(!fire_backwards && distance < 20.0f) );
|
||||
if(m_controls->getFire())
|
||||
m_controls->setLookBack(fire_backwards);
|
||||
break;
|
||||
} // POWERUP_CAKE
|
||||
|
||||
@ -1338,12 +1337,12 @@ void SkiddingAI::handleItems(const float dt)
|
||||
|
||||
float distance = fire_backwards ? m_distance_behind
|
||||
: m_distance_ahead;
|
||||
m_controls->m_fire = ( (fire_backwards && distance < 30.0f) ||
|
||||
m_controls->setFire( ( (fire_backwards && distance < 30.0f) ||
|
||||
(!fire_backwards && distance <10.0f) ) &&
|
||||
m_time_since_last_shot > 3.0f &&
|
||||
(straight_behind || straight_ahead);
|
||||
if(m_controls->m_fire)
|
||||
m_controls->m_look_back = fire_backwards;
|
||||
(straight_behind || straight_ahead) );
|
||||
if(m_controls->getFire())
|
||||
m_controls->setLookBack(fire_backwards);
|
||||
break;
|
||||
} // POWERUP_BOWLING
|
||||
|
||||
@ -1369,10 +1368,10 @@ void SkiddingAI::handleItems(const float dt)
|
||||
!m_kart_ahead;
|
||||
float distance = fire_backwards ? m_distance_behind
|
||||
: m_distance_ahead;
|
||||
m_controls->m_fire = distance < 30.0f ||
|
||||
m_time_since_last_shot > 10.0f;
|
||||
if(m_controls->m_fire)
|
||||
m_controls->m_look_back = fire_backwards;
|
||||
m_controls->setFire(distance < 30.0f ||
|
||||
m_time_since_last_shot > 10.0f );
|
||||
if(m_controls->getFire())
|
||||
m_controls->setLookBack(fire_backwards);
|
||||
break;
|
||||
} // POWERUP_PLUNGER
|
||||
|
||||
@ -1382,13 +1381,13 @@ void SkiddingAI::handleItems(const float dt)
|
||||
// after a waiting an appropriate time
|
||||
if(m_kart->getPosition()>1 &&
|
||||
m_time_since_last_shot > stk_config->m_item_switch_time+2.0f)
|
||||
m_controls->m_fire = true;
|
||||
m_controls->setFire(true);
|
||||
break; // POWERUP_SWITCH
|
||||
|
||||
case PowerupManager::POWERUP_PARACHUTE:
|
||||
// Wait one second more than a previous parachute
|
||||
if(m_time_since_last_shot > m_kart->getKartProperties()->getParachuteDurationOther() + 1.0f)
|
||||
m_controls->m_fire = true;
|
||||
m_controls->setFire(true);
|
||||
break; // POWERUP_PARACHUTE
|
||||
|
||||
case PowerupManager::POWERUP_ANVIL:
|
||||
@ -1397,13 +1396,13 @@ void SkiddingAI::handleItems(const float dt)
|
||||
|
||||
if(race_manager->getMinorMode()==RaceManager::MINOR_MODE_FOLLOW_LEADER)
|
||||
{
|
||||
m_controls->m_fire = m_world->getTime()<1.0f &&
|
||||
m_kart->getPosition()>2;
|
||||
m_controls->setFire(m_world->getTime()<1.0f &&
|
||||
m_kart->getPosition()>2 );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_controls->m_fire = m_time_since_last_shot > 3.0f &&
|
||||
m_kart->getPosition()>1;
|
||||
m_controls->setFire(m_time_since_last_shot > 3.0f &&
|
||||
m_kart->getPosition()>1 );
|
||||
}
|
||||
break; // POWERUP_ANVIL
|
||||
|
||||
@ -1424,7 +1423,7 @@ void SkiddingAI::handleItems(const float dt)
|
||||
m_kart_ahead->getSpeed() < m_kart->getSpeed() ) ||
|
||||
( m_kart_behind && !m_kart_behind->isSquashed() &&
|
||||
(m_kart_behind->getXYZ()-m_kart->getXYZ()).length2()<d2) )
|
||||
m_controls->m_fire = true;
|
||||
m_controls->setFire(true);
|
||||
break;
|
||||
}
|
||||
case PowerupManager::POWERUP_RUBBERBALL:
|
||||
@ -1434,7 +1433,7 @@ void SkiddingAI::handleItems(const float dt)
|
||||
// Perhaps some more sophisticated algorithm might be useful.
|
||||
// For now: fire if there is a kart ahead (which means that
|
||||
// this kart is certainly not the first kart)
|
||||
m_controls->m_fire = m_kart_ahead != NULL;
|
||||
m_controls->setFire(m_kart_ahead != NULL);
|
||||
break;
|
||||
default:
|
||||
Log::error(getControllerName().c_str(),
|
||||
@ -1442,7 +1441,7 @@ void SkiddingAI::handleItems(const float dt)
|
||||
m_kart->getPowerup()->getType());
|
||||
assert(false);
|
||||
}
|
||||
if(m_controls->m_fire) m_time_since_last_shot = 0.0f;
|
||||
if(m_controls->getFire()) m_time_since_last_shot = 0.0f;
|
||||
} // handleItems
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -1518,7 +1517,7 @@ void SkiddingAI::handleAcceleration( const float dt)
|
||||
if( m_start_delay > 0.0f )
|
||||
{
|
||||
m_start_delay -= dt;
|
||||
m_controls->m_accel = 0.0f;
|
||||
m_controls->setAccel(0.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1526,22 +1525,22 @@ void SkiddingAI::handleAcceleration( const float dt)
|
||||
// m_brake has not been reset from the previous frame, which can
|
||||
// cause too long slow downs. On the other hand removing it appears
|
||||
// to decrease performance in some narrower tracks
|
||||
if( m_controls->m_brake )
|
||||
if( m_controls->getBrake())
|
||||
{
|
||||
m_controls->m_accel = 0.0f;
|
||||
m_controls->setAccel(0.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_kart->getBlockedByPlungerTime()>0)
|
||||
{
|
||||
if(m_kart->getSpeed() < m_kart->getCurrentMaxSpeed() / 2)
|
||||
m_controls->m_accel = 0.05f;
|
||||
m_controls->setAccel(0.05f);
|
||||
else
|
||||
m_controls->m_accel = 0.0f;
|
||||
m_controls->setAccel(0.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
m_controls->m_accel = stk_config->m_ai_acceleration;
|
||||
m_controls->setAccel(stk_config->m_ai_acceleration);
|
||||
|
||||
} // handleAcceleration
|
||||
|
||||
@ -1598,7 +1597,7 @@ void SkiddingAI::handleRescue(const float dt)
|
||||
*/
|
||||
void SkiddingAI::handleNitroAndZipper()
|
||||
{
|
||||
m_controls->m_nitro = false;
|
||||
m_controls->setNitro(false);
|
||||
|
||||
// The next line prevents usage of nitro on long straights, where the kart
|
||||
// is already fast.
|
||||
@ -1607,14 +1606,14 @@ void SkiddingAI::handleNitroAndZipper()
|
||||
if(m_kart->getSpeed() > 0.95f*m_kart->getCurrentMaxSpeed())
|
||||
return;
|
||||
// About the above: removing this line might enable the AI to better use
|
||||
// nitro and zippers .
|
||||
// nitro and zippers.
|
||||
// This works well for some tracks (math, lighthouse
|
||||
// sandtrack), but worse in others (zen, xr591). The good result
|
||||
// is caused by long straights in which the AI will now use zippers,
|
||||
// but in the other tracks the high speed causes karts to crash in
|
||||
// tight corners. In some cases it would need a reasonable large 'lookahead'
|
||||
// to know that at a certain spot a zipper or skidding should not be used
|
||||
// (e.g. in xr591, left at the fork - new AI will nearly always fell of the
|
||||
// (e.g. in xr591, left at the fork - new AI will nearly always fall off the
|
||||
// track after the curve). Here the summarised results of 10 laps runs with
|
||||
// 4 old against 4 new AIs in time trail mode. The 'gain' is the sum of all
|
||||
// (star_positions-end_positions). So a gain of -10 means that basically
|
||||
@ -1645,7 +1644,7 @@ void SkiddingAI::handleNitroAndZipper()
|
||||
if(m_kart->getBlockedByPlungerTime()>0) return;
|
||||
|
||||
// Don't use nitro if we are braking
|
||||
if(m_controls->m_brake) return;
|
||||
if(m_controls->getBrake()) return;
|
||||
|
||||
// Don't use nitro if the kart is not on ground or has finished the race
|
||||
if(!m_kart->isOnGround() || m_kart->hasFinishedRace()) return;
|
||||
@ -1675,7 +1674,7 @@ void SkiddingAI::handleNitroAndZipper()
|
||||
// If the kart is very slow (e.g. after rescue), use nitro
|
||||
if(m_kart->getSpeed()<5)
|
||||
{
|
||||
m_controls->m_nitro = true;
|
||||
m_controls->setNitro(true);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1686,7 +1685,7 @@ void SkiddingAI::handleNitroAndZipper()
|
||||
if(m_kart->getPosition()== (int)num_karts &&
|
||||
num_karts>1 && m_kart->getEnergy()>2.0f)
|
||||
{
|
||||
m_controls->m_nitro = true;
|
||||
m_controls->setNitro(true);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1702,7 +1701,7 @@ void SkiddingAI::handleNitroAndZipper()
|
||||
m_world->getEstimatedFinishTime(m_kart->getWorldKartId());
|
||||
if( 1.5f*m_kart->getEnergy() >= finish - m_world->getTime() )
|
||||
{
|
||||
m_controls->m_nitro = true;
|
||||
m_controls->setNitro(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -1718,7 +1717,7 @@ void SkiddingAI::handleNitroAndZipper()
|
||||
m_distance_ahead < overtake_distance &&
|
||||
m_kart_ahead->getSpeed()+5.0f > m_kart->getSpeed() )
|
||||
{
|
||||
m_controls->m_nitro = true;
|
||||
m_controls->setNitro(true);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1727,8 +1726,8 @@ void SkiddingAI::handleNitroAndZipper()
|
||||
m_kart_behind->getSpeed() > m_kart->getSpeed() )
|
||||
{
|
||||
// Only prevent overtaking on highest level
|
||||
m_controls->m_nitro = m_ai_properties->m_nitro_usage
|
||||
== AIProperties::NITRO_ALL;
|
||||
m_controls->setNitro(m_ai_properties->m_nitro_usage
|
||||
== AIProperties::NITRO_ALL );
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1746,7 +1745,7 @@ void SkiddingAI::handleNitroAndZipper()
|
||||
- DriveGraph::get()->getDistanceFromStart(m_track_node);
|
||||
if(diff<0) diff+=World::getWorld()->getTrack()->getTrackLength();
|
||||
if(diff>m_ai_properties->m_straight_length_for_zipper)
|
||||
m_controls->m_fire = true;
|
||||
m_controls->setFire(true);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1983,7 +1982,6 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node)
|
||||
m_curve[CURVE_KART]->addPoint(m_kart->getTrans()(forw)+eps);
|
||||
#endif
|
||||
*last_node = m_next_node_index[m_track_node];
|
||||
int target_sector;
|
||||
|
||||
Vec3 direction;
|
||||
Vec3 step_track_coord;
|
||||
@ -1995,7 +1993,7 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node)
|
||||
{
|
||||
// target_sector is the sector at the longest distance that we can
|
||||
// drive to without crashing with the track.
|
||||
target_sector = m_next_node_index[*last_node];
|
||||
int target_sector = m_next_node_index[*last_node];
|
||||
|
||||
//direction is a vector from our kart to the sectors we are testing
|
||||
direction = DriveGraph::get()->getNode(target_sector)->getCenter()
|
||||
@ -2079,12 +2077,9 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node)
|
||||
*last_node = m_next_node_index[m_track_node];
|
||||
float angle = DriveGraph::get()->getAngleToNext(m_track_node,
|
||||
m_successor_index[m_track_node]);
|
||||
int target_sector;
|
||||
|
||||
Vec3 direction;
|
||||
Vec3 step_track_coord;
|
||||
|
||||
float angle1;
|
||||
// The original while(1) loop is replaced with a for loop to avoid
|
||||
// infinite loops (which we had once or twice). Usually the number
|
||||
// of iterations in the while loop is less than 7.
|
||||
@ -2092,8 +2087,8 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node)
|
||||
{
|
||||
// target_sector is the sector at the longest distance that we can
|
||||
// drive to without crashing with the track.
|
||||
target_sector = m_next_node_index[*last_node];
|
||||
angle1 = DriveGraph::get()->getAngleToNext(target_sector,
|
||||
int target_sector = m_next_node_index[*last_node];
|
||||
float angle1 = DriveGraph::get()->getAngleToNext(target_sector,
|
||||
m_successor_index[target_sector]);
|
||||
// In very sharp turns this algorithm tends to aim at off track points,
|
||||
// resulting in hitting a corner. So test for this special case and
|
||||
@ -2280,7 +2275,7 @@ bool SkiddingAI::canSkid(float steer_fraction)
|
||||
// If the kart has to do a sharp turn, but is already skidding, find
|
||||
// a good time to release the skid button, since this will turn the
|
||||
// kart more sharply:
|
||||
if(m_controls->m_skid)
|
||||
if(m_controls->getSkidControl())
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if(m_ai_debug)
|
||||
@ -2305,7 +2300,7 @@ bool SkiddingAI::canSkid(float steer_fraction)
|
||||
m_current_track_direction==DriveNode::DIR_UNDEFINED )
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if(m_controls->m_skid && m_ai_debug)
|
||||
if(m_controls->getSkidControl() && m_ai_debug)
|
||||
{
|
||||
Log::debug(getControllerName().c_str(),
|
||||
"%s stops skidding on straight.",
|
||||
@ -2342,7 +2337,7 @@ bool SkiddingAI::canSkid(float steer_fraction)
|
||||
|
||||
// If the remaining estimated time for skidding is too short, stop
|
||||
// it. This code will mostly trigger the bonus at the end of a skid.
|
||||
if(m_controls->m_skid && duration < 1.0f)
|
||||
if(m_controls->getSkidControl() && duration < 1.0f)
|
||||
{
|
||||
if(m_ai_debug)
|
||||
Log::debug(getControllerName().c_str(),
|
||||
@ -2360,7 +2355,7 @@ bool SkiddingAI::canSkid(float steer_fraction)
|
||||
m_current_track_direction==DriveNode::DIR_RIGHT) )
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if(m_controls->m_skid && m_ai_debug)
|
||||
if(m_controls->getSkidControl() && m_ai_debug)
|
||||
Log::debug(getControllerName().c_str(),
|
||||
"%s skidding against track direction.",
|
||||
m_kart->getIdent().c_str());
|
||||
@ -2372,7 +2367,7 @@ bool SkiddingAI::canSkid(float steer_fraction)
|
||||
m_kart->getKartProperties()->getSkidTimeTillBonus()[0] < duration)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if(!m_controls->m_skid && m_ai_debug)
|
||||
if(!m_controls->getSkidControl() && m_ai_debug)
|
||||
Log::debug(getControllerName().c_str(),
|
||||
"%s start skid, duration %f.",
|
||||
m_kart->getIdent().c_str(), duration);
|
||||
@ -2382,7 +2377,7 @@ bool SkiddingAI::canSkid(float steer_fraction)
|
||||
} // if curve long enough for skidding
|
||||
|
||||
#ifdef DEBUG
|
||||
if(m_controls->m_skid && m_ai_debug)
|
||||
if(m_controls->getSkidControl() && m_ai_debug)
|
||||
Log::debug(getControllerName().c_str(),
|
||||
"%s has no reasons to skid anymore.",
|
||||
m_kart->getIdent().c_str());
|
||||
@ -2413,7 +2408,7 @@ void SkiddingAI::setSteering(float angle, float dt)
|
||||
if(!canSkid(steer_fraction))
|
||||
{
|
||||
m_skid_probability_state = SKID_PROBAB_NOT_YET;
|
||||
m_controls->m_skid = KartControl::SC_NONE;
|
||||
m_controls->setSkidControl(KartControl::SC_NONE);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2436,8 +2431,8 @@ void SkiddingAI::setSteering(float angle, float dt)
|
||||
sc= ? "no" : sc==KartControl::SC_LEFT ? "left" : "right");
|
||||
#endif
|
||||
}
|
||||
m_controls->m_skid = m_skid_probability_state == SKID_PROBAB_SKID
|
||||
? sc : KartControl::SC_NONE;
|
||||
m_controls->setSkidControl(m_skid_probability_state == SKID_PROBAB_SKID
|
||||
? sc : KartControl::SC_NONE );
|
||||
}
|
||||
|
||||
// Adjust steer fraction in case to be in [-1,1]
|
||||
@ -2461,7 +2456,7 @@ void SkiddingAI::setSteering(float angle, float dt)
|
||||
if((ss==Skidding::SKID_ACCUMULATE_LEFT && steer_fraction>0.2f ) ||
|
||||
(ss==Skidding::SKID_ACCUMULATE_RIGHT && steer_fraction<-0.2f) )
|
||||
{
|
||||
m_controls->m_skid = KartControl::SC_NONE;
|
||||
m_controls->setSkidControl(KartControl::SC_NONE);
|
||||
#ifdef DEBUG
|
||||
if(m_ai_debug)
|
||||
Log::info(getControllerName().c_str(),
|
||||
@ -2470,7 +2465,7 @@ void SkiddingAI::setSteering(float angle, float dt)
|
||||
#endif
|
||||
}
|
||||
|
||||
if(m_controls->m_skid!=KartControl::SC_NONE &&
|
||||
if(m_controls->getSkidControl()!=KartControl::SC_NONE &&
|
||||
( ss==Skidding::SKID_ACCUMULATE_LEFT ||
|
||||
ss==Skidding::SKID_ACCUMULATE_RIGHT ) )
|
||||
{
|
||||
@ -2484,7 +2479,7 @@ void SkiddingAI::setSteering(float angle, float dt)
|
||||
"%s steering too much (%f).",
|
||||
m_kart->getIdent().c_str(), steer_fraction);
|
||||
#endif
|
||||
m_controls->m_skid = KartControl::SC_NONE;
|
||||
m_controls->setSkidControl(KartControl::SC_NONE);
|
||||
}
|
||||
if(steer_fraction<-1.0f)
|
||||
steer_fraction = -1.0f;
|
||||
@ -2492,19 +2487,19 @@ void SkiddingAI::setSteering(float angle, float dt)
|
||||
steer_fraction = 1.0f;
|
||||
}
|
||||
|
||||
float old_steer = m_controls->m_steer;
|
||||
float old_steer = m_controls->getSteer();
|
||||
|
||||
// The AI has its own 'time full steer' value (which is the time
|
||||
float max_steer_change = dt/m_ai_properties->m_time_full_steer;
|
||||
if(old_steer < steer_fraction)
|
||||
{
|
||||
m_controls->m_steer = (old_steer+max_steer_change > steer_fraction)
|
||||
? steer_fraction : old_steer+max_steer_change;
|
||||
m_controls->setSteer( (old_steer+max_steer_change > steer_fraction)
|
||||
? steer_fraction : old_steer+max_steer_change );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_controls->m_steer = (old_steer-max_steer_change < steer_fraction)
|
||||
? steer_fraction : old_steer-max_steer_change;
|
||||
m_controls->setSteer( (old_steer-max_steer_change < steer_fraction)
|
||||
? steer_fraction : old_steer-max_steer_change );
|
||||
}
|
||||
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#include "karts/kart.hpp"
|
||||
#include "graphics/central_settings.hpp"
|
||||
|
||||
#include "audio/sfx_manager.hpp"
|
||||
#include "audio/sfx_base.hpp"
|
||||
#include "challenges/challenge_status.hpp"
|
||||
@ -27,6 +27,7 @@
|
||||
#include "config/user_config.hpp"
|
||||
#include "font/bold_face.hpp"
|
||||
#include "graphics/camera.hpp"
|
||||
#include "graphics/central_settings.hpp"
|
||||
#include "graphics/explosion.hpp"
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "graphics/material_manager.hpp"
|
||||
@ -40,25 +41,33 @@
|
||||
#include "graphics/stk_text_billboard.hpp"
|
||||
#include "graphics/stars.hpp"
|
||||
#include "guiengine/scalable_font.hpp"
|
||||
#include "karts/explosion_animation.hpp"
|
||||
#include "karts/kart_gfx.hpp"
|
||||
#include "karts/rescue_animation.hpp"
|
||||
#include "modes/overworld.hpp"
|
||||
#include "modes/soccer_world.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "io/file_manager.hpp"
|
||||
#include "items/attachment.hpp"
|
||||
#include "items/item_manager.hpp"
|
||||
#include "items/powerup.hpp"
|
||||
#include "items/projectile_manager.hpp"
|
||||
#include "karts/controller/end_controller.hpp"
|
||||
#include "karts/abstract_characteristic.hpp"
|
||||
#include "karts/abstract_kart_animation.hpp"
|
||||
#include "karts/cached_characteristic.hpp"
|
||||
#include "karts/controller/end_controller.hpp"
|
||||
#include "karts/explosion_animation.hpp"
|
||||
#include "karts/kart_gfx.hpp"
|
||||
#include "karts/kart_model.hpp"
|
||||
#include "karts/kart_properties_manager.hpp"
|
||||
#include "karts/kart_rewinder.hpp"
|
||||
#include "karts/max_speed.hpp"
|
||||
#include "karts/rescue_animation.hpp"
|
||||
#include "karts/skidding.hpp"
|
||||
#include "modes/overworld.hpp"
|
||||
#include "modes/soccer_world.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "modes/linear_world.hpp"
|
||||
#include "modes/overworld.hpp"
|
||||
#include "modes/soccer_world.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
#include "network/race_event_manager.hpp"
|
||||
#include "network/rewind_manager.hpp"
|
||||
#include "physics/btKart.hpp"
|
||||
#include "physics/btKartRaycast.hpp"
|
||||
#include "physics/physics.hpp"
|
||||
@ -81,6 +90,13 @@
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
|
||||
#include <math.h>
|
||||
#include <iostream>
|
||||
#include <algorithm> // for min and max
|
||||
|
||||
#include <ICameraSceneNode.h>
|
||||
#include <ISceneManager.h>
|
||||
|
||||
|
||||
#if defined(WIN32) && !defined(__CYGWIN__) && !defined(__MINGW32__)
|
||||
// Disable warning for using 'this' in base member initializer list
|
||||
@ -143,6 +159,7 @@ Kart::Kart (const std::string& ident, unsigned int world_kart_id,
|
||||
// Set position and heading:
|
||||
m_reset_transform = init_transform;
|
||||
m_speed = 0.0f;
|
||||
m_smoothed_speed = 0.0f;
|
||||
|
||||
m_kart_model->setKart(this);
|
||||
|
||||
@ -342,6 +359,7 @@ void Kart::reset()
|
||||
m_brake_time = 0.0f;
|
||||
m_time_last_crash = 0.0f;
|
||||
m_speed = 0.0f;
|
||||
m_smoothed_speed = 0.0f;
|
||||
m_current_lean = 0.0f;
|
||||
m_view_blocked_by_plunger = 0.0f;
|
||||
m_bubblegum_time = 0.0f;
|
||||
@ -1164,18 +1182,8 @@ void Kart::eliminate()
|
||||
*/
|
||||
void Kart::update(float dt)
|
||||
{
|
||||
#ifdef DEBUG_TO_COMPARE_KART_PHYSICS
|
||||
// This information is useful when comparing kart physics, e.g. to
|
||||
// see top speed, acceleration (i.e. time to top speed) etc.
|
||||
Log::verbose("physics", "%s t %f xyz %f %f %f %f v %f %f %f %f maxv %f",
|
||||
getIdent().c_str(),
|
||||
World::getWorld()->getTime(),
|
||||
getXYZ().getX(), getXYZ().getY(), getXYZ().getZ(),
|
||||
getXYZ().length(),
|
||||
getVelocity().getX(), getVelocity().getY(), getVelocity().getZ(),
|
||||
getVelocity().length(),
|
||||
m_max_speed->getCurrentMaxSpeed());
|
||||
#endif
|
||||
// Reset any instand speed increase in the bullet kart
|
||||
m_vehicle->resetInstantSpeed();
|
||||
|
||||
// update star effect (call will do nothing if stars are not activated)
|
||||
m_stars_effect->update(dt);
|
||||
@ -1213,10 +1221,44 @@ void Kart::update(float dt)
|
||||
|
||||
Vec3 front(0, 0, getKartLength()*0.5f);
|
||||
m_xyz_front = getTrans()(front);
|
||||
// Update the locally maintained speed of the kart (m_speed), which
|
||||
// is used furthermore for engine power, camera distance etc
|
||||
updateSpeed();
|
||||
|
||||
if(!history->replayHistory())
|
||||
if(!history->replayHistory() && !RewindManager::get()->isRewinding())
|
||||
m_controller->update(dt);
|
||||
|
||||
#undef DEBUG_CAMERA_SHAKE
|
||||
#ifdef DEBUG_CAMERA_SHAKE
|
||||
Log::verbose("camera", "%s t %f %f xyz %f %f %f v %f %f %f d3 %f d2 %f",
|
||||
getIdent().c_str(),
|
||||
World::getWorld()->getTime(), dt,
|
||||
getXYZ().getX(), getXYZ().getY(), getXYZ().getZ(),
|
||||
getVelocity().getX(), getVelocity().getY(), getVelocity().getZ(),
|
||||
(Camera::getCamera(0)->getXYZ()-getXYZ()).length(),
|
||||
(Camera::getCamera(0)->getXYZ()-getXYZ()).length_2d()
|
||||
);
|
||||
#endif
|
||||
|
||||
#undef DEBUG_TO_COMPARE_KART_PHYSICS
|
||||
#ifdef DEBUG_TO_COMPARE_KART_PHYSICS
|
||||
// This information is useful when comparing kart physics, e.g. to
|
||||
// see top speed, acceleration (i.e. time to top speed) etc.
|
||||
Log::verbose("physics", "%s t %f %f xyz %f %f %f v %f %f %f sk %f %d %f %f %f st %f %f",
|
||||
getIdent().c_str(),
|
||||
World::getWorld()->getTime(), dt,
|
||||
getXYZ().getX(), getXYZ().getY(), getXYZ().getZ(),
|
||||
getVelocity().getX(), getVelocity().getY(), getVelocity().getZ(),
|
||||
m_skidding->getSkidFactor(),
|
||||
m_skidding->getSkidState(),
|
||||
m_skidding->getSteeringFraction(),
|
||||
getMaxSteerAngle(),
|
||||
m_speed,
|
||||
m_vehicle->getWheelInfo(0).m_steering,
|
||||
m_vehicle->getWheelInfo(1).m_steering
|
||||
);
|
||||
#endif
|
||||
|
||||
// if its view is blocked by plunger, decrease remaining time
|
||||
if(m_view_blocked_by_plunger > 0) m_view_blocked_by_plunger -= dt;
|
||||
//unblock the view if kart just became shielded
|
||||
@ -1271,9 +1313,9 @@ void Kart::update(float dt)
|
||||
updatePhysics(dt);
|
||||
PROFILER_POP_CPU_MARKER();
|
||||
|
||||
if(!m_controls.m_fire) m_fire_clicked = 0;
|
||||
if(!m_controls.getFire()) m_fire_clicked = 0;
|
||||
|
||||
if(m_controls.m_fire && !m_fire_clicked && !m_kart_animation)
|
||||
if(m_controls.getFire() && !m_fire_clicked && !m_kart_animation)
|
||||
{
|
||||
// use() needs to be called even if there currently is no collecteable
|
||||
// since use() can test if something needs to be switched on/off.
|
||||
@ -1510,6 +1552,47 @@ void Kart::update(float dt)
|
||||
|
||||
} // update
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Updates the local speed based on the current physical velocity. The value
|
||||
* is smoothed exponentially to avoid camera stuttering (camera distance
|
||||
* is dependent on speed)
|
||||
*/
|
||||
void Kart::updateSpeed()
|
||||
{
|
||||
// Compute the speed of the kart. Smooth it with previous speed to make
|
||||
// the camera smoother (because of capping the speed in m_max_speed
|
||||
// the speed value jitters when approaching maximum speed. This results
|
||||
// in the distance between kart and camera to jitter as well (typically
|
||||
// only in the order of centimetres though). Smoothing the speed value
|
||||
// gets rid of this jitter, and also r
|
||||
m_speed = getVehicle()->getRigidBody()->getLinearVelocity().length();
|
||||
|
||||
// calculate direction of m_speed
|
||||
const btTransform& chassisTrans = getVehicle()->getChassisWorldTransform();
|
||||
btVector3 forwardW(
|
||||
chassisTrans.getBasis()[0][2],
|
||||
chassisTrans.getBasis()[1][2],
|
||||
chassisTrans.getBasis()[2][2]);
|
||||
|
||||
if (forwardW.dot(getVehicle()->getRigidBody()->getLinearVelocity()) < btScalar(0.))
|
||||
{
|
||||
m_speed = -m_speed;
|
||||
}
|
||||
|
||||
float f = 0.3f;
|
||||
m_smoothed_speed = f*m_speed + (1.0f - f)*m_smoothed_speed;
|
||||
|
||||
// At low velocity, forces on kart push it back and forth so we ignore this
|
||||
// - quick'n'dirty workaround for bug 1776883
|
||||
if (fabsf(m_speed) < 0.2f ||
|
||||
dynamic_cast<RescueAnimation*> ( getKartAnimation() ) ||
|
||||
dynamic_cast<ExplosionAnimation*>( getKartAnimation() ) )
|
||||
{
|
||||
m_speed = 0;
|
||||
m_smoothed_speed = 0;
|
||||
}
|
||||
} // updateSpeed
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Show fire to go with a zipper.
|
||||
*/
|
||||
@ -1799,7 +1882,7 @@ void Kart::handleZipper(const Material *material, bool play_sound)
|
||||
engine_force = m_kart_properties->getZipperForce();
|
||||
}
|
||||
// Ignore a zipper that's activated while braking
|
||||
if(m_controls.m_brake || m_speed<0) return;
|
||||
if(m_controls.getBrake() || m_speed<0) return;
|
||||
|
||||
m_max_speed->instantSpeedIncrease(MaxSpeed::MS_INCREASE_ZIPPER,
|
||||
max_speed_increase, speed_gain,
|
||||
@ -1815,7 +1898,7 @@ void Kart::handleZipper(const Material *material, bool play_sound)
|
||||
*/
|
||||
void Kart::updateNitro(float dt)
|
||||
{
|
||||
if (m_controls.m_nitro && m_min_nitro_time <= 0.0f)
|
||||
if (m_controls.getNitro() && m_min_nitro_time <= 0.0f)
|
||||
{
|
||||
m_min_nitro_time = m_kart_properties->getNitroMinConsumptionTime();
|
||||
}
|
||||
@ -1825,11 +1908,11 @@ void Kart::updateNitro(float dt)
|
||||
|
||||
// when pressing the key, don't allow the min time to go under zero.
|
||||
// If it went under zero, it would be reset
|
||||
if (m_controls.m_nitro && m_min_nitro_time <= 0.0f)
|
||||
if (m_controls.getNitro() && m_min_nitro_time <= 0.0f)
|
||||
m_min_nitro_time = 0.1f;
|
||||
}
|
||||
|
||||
bool increase_speed = (m_controls.m_nitro && isOnGround());
|
||||
bool increase_speed = (m_controls.getNitro() && isOnGround());
|
||||
if (!increase_speed && m_min_nitro_time <= 0.0f)
|
||||
{
|
||||
if(m_nitro_sound->getStatus() == SFXBase::SFX_PLAYING)
|
||||
@ -2140,16 +2223,19 @@ void Kart::updatePhysics(float dt)
|
||||
// Check if accel is pressed for the first time. The actual timing
|
||||
// is done in getStartupBoost - it returns 0 if the start was actually
|
||||
// too slow to qualify for a boost.
|
||||
if(!m_has_started && m_controls.m_accel)
|
||||
if(!m_has_started && m_controls.getAccel())
|
||||
{
|
||||
m_has_started = true;
|
||||
float f = getStartupBoost();
|
||||
if(f >= 0.0f) m_kart_gfx->setCreationRateAbsolute(KartGFX::KGFX_ZIPPER, 100*f);
|
||||
m_max_speed->instantSpeedIncrease(MaxSpeed::MS_INCREASE_ZIPPER,
|
||||
0.9f*f, f,
|
||||
/*engine_force*/200.0f,
|
||||
/*duration*/5.0f,
|
||||
/*fade_out_time*/5.0f);
|
||||
if(f >= 0.0f)
|
||||
{
|
||||
m_kart_gfx->setCreationRateAbsolute(KartGFX::KGFX_ZIPPER, 100*f);
|
||||
m_max_speed->instantSpeedIncrease(MaxSpeed::MS_INCREASE_ZIPPER,
|
||||
0.9f*f, f,
|
||||
/*engine_force*/200.0f,
|
||||
/*duration*/5.0f,
|
||||
/*fade_out_time*/5.0f);
|
||||
}
|
||||
}
|
||||
|
||||
m_bounce_back_time-=dt;
|
||||
@ -2160,8 +2246,8 @@ void Kart::updatePhysics(float dt)
|
||||
if (m_flying)
|
||||
updateFlying();
|
||||
|
||||
m_skidding->update(dt, isOnGround(), m_controls.m_steer,
|
||||
m_controls.m_skid);
|
||||
m_skidding->update(dt, isOnGround(), m_controls.getSteer(),
|
||||
m_controls.getSkidControl());
|
||||
m_vehicle->setVisualRotation(m_skidding->getVisualSkidRotation());
|
||||
if(( m_skidding->getSkidState() == Skidding::SKID_ACCUMULATE_LEFT ||
|
||||
m_skidding->getSkidState() == Skidding::SKID_ACCUMULATE_RIGHT ) &&
|
||||
@ -2181,19 +2267,6 @@ void Kart::updatePhysics(float dt)
|
||||
|
||||
updateSliding();
|
||||
|
||||
// Compute the speed of the kart.
|
||||
m_speed = getVehicle()->getRigidBody()->getLinearVelocity().length();
|
||||
|
||||
// calculate direction of m_speed
|
||||
const btTransform& chassisTrans = getVehicle()->getChassisWorldTransform();
|
||||
btVector3 forwardW (
|
||||
chassisTrans.getBasis()[0][2],
|
||||
chassisTrans.getBasis()[1][2],
|
||||
chassisTrans.getBasis()[2][2]);
|
||||
|
||||
if (forwardW.dot(getVehicle()->getRigidBody()->getLinearVelocity()) < btScalar(0.))
|
||||
m_speed *= -1.f;
|
||||
|
||||
// Cap speed if necessary
|
||||
const Material *m = getMaterial();
|
||||
|
||||
@ -2201,34 +2274,6 @@ void Kart::updatePhysics(float dt)
|
||||
m_max_speed->setMinSpeed(min_speed);
|
||||
m_max_speed->update(dt);
|
||||
|
||||
// To avoid tunneling (which can happen on long falls), clamp the
|
||||
// velocity in Y direction. Tunneling can happen if the Y velocity
|
||||
// is larger than the maximum suspension travel (per frame), since then
|
||||
// the wheel suspension can not stop/slow down the fall (though I am
|
||||
// not sure if this is enough in all cases!). So the speed is limited
|
||||
// to suspensionTravel / dt with dt = 1/60 (since this is the dt
|
||||
// bullet is using).
|
||||
|
||||
// Only apply if near ground instead of purely based on speed avoiding
|
||||
// the "parachute on top" look.
|
||||
const Vec3 &v = m_body->getLinearVelocity();
|
||||
if(/*isNearGround() &&*/ v.getY() < - m_kart_properties->getSuspensionTravel() * 60)
|
||||
{
|
||||
Vec3 v_clamped = v;
|
||||
// clamp the speed to 99% of the maxium falling speed.
|
||||
v_clamped.setY(-m_kart_properties->getSuspensionTravel() * 60 * 0.99f);
|
||||
//m_body->setLinearVelocity(v_clamped);
|
||||
}
|
||||
|
||||
//at low velocity, forces on kart push it back and forth so we ignore this
|
||||
if(fabsf(m_speed) < 0.2f) // quick'n'dirty workaround for bug 1776883
|
||||
m_speed = 0;
|
||||
|
||||
if (dynamic_cast<RescueAnimation*>(getKartAnimation()) ||
|
||||
dynamic_cast<ExplosionAnimation*>(getKartAnimation()))
|
||||
{
|
||||
m_speed = 0;
|
||||
}
|
||||
|
||||
updateEngineSFX();
|
||||
#ifdef XX
|
||||
@ -2244,7 +2289,7 @@ void Kart::updatePhysics(float dt)
|
||||
);
|
||||
#endif
|
||||
|
||||
} // updatePhysics
|
||||
} // updatephysics
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Adjust the engine sound effect depending on the speed of the kart.
|
||||
@ -2301,7 +2346,7 @@ void Kart::updateEnginePowerAndBrakes(float dt)
|
||||
m_body->applyTorque(btVector3(0.0, m_bubblegum_torque, 0.0));
|
||||
}
|
||||
|
||||
if(m_controls.m_accel) // accelerating
|
||||
if(m_controls.getAccel()) // accelerating
|
||||
{
|
||||
// For a short time after a collision disable the engine,
|
||||
// so that the karts can bounce back a bit from the obstacle.
|
||||
@ -2314,11 +2359,11 @@ void Kart::updateEnginePowerAndBrakes(float dt)
|
||||
engine_power *= 5.0f;
|
||||
|
||||
// Lose some traction when skidding, to balance the advantage
|
||||
if (m_controls.m_skid &&
|
||||
if (m_controls.getSkidControl() &&
|
||||
m_kart_properties->getSkidVisualTime() == 0)
|
||||
engine_power *= 0.5f;
|
||||
|
||||
applyEngineForce(engine_power*m_controls.m_accel);
|
||||
applyEngineForce(engine_power*m_controls.getAccel());
|
||||
|
||||
// Either all or no brake is set, so test only one to avoid
|
||||
// resetting all brakes most of the time.
|
||||
@ -2329,7 +2374,7 @@ void Kart::updateEnginePowerAndBrakes(float dt)
|
||||
}
|
||||
else
|
||||
{ // not accelerating
|
||||
if(m_controls.m_brake)
|
||||
if(m_controls.getBrake())
|
||||
{ // check if the player is currently only slowing down
|
||||
// or moving backwards
|
||||
if(m_speed > 0.0f)
|
||||
@ -2365,9 +2410,9 @@ void Kart::updateEnginePowerAndBrakes(float dt)
|
||||
{
|
||||
m_brake_time = 0;
|
||||
// lift the foot from throttle, brakes with 10% engine_power
|
||||
assert(!std::isnan(m_controls.m_accel));
|
||||
assert(!std::isnan(m_controls.getAccel()));
|
||||
assert(!std::isnan(engine_power));
|
||||
applyEngineForce(-m_controls.m_accel*engine_power*0.1f);
|
||||
applyEngineForce(-m_controls.getAccel()*engine_power*0.1f);
|
||||
|
||||
// If not giving power (forward or reverse gear), and speed is low
|
||||
// we are "parking" the kart, so in battle mode we can ambush people
|
||||
@ -2436,7 +2481,7 @@ void Kart::updateFlying()
|
||||
{
|
||||
m_body->setLinearVelocity(m_body->getLinearVelocity() * 0.99f);
|
||||
|
||||
if (m_controls.m_accel)
|
||||
if (m_controls.getAccel())
|
||||
{
|
||||
btVector3 velocity = m_body->getLinearVelocity();
|
||||
if (velocity.length() < 25)
|
||||
@ -2446,7 +2491,7 @@ void Kart::updateFlying()
|
||||
100.0f*cos(orientation)));
|
||||
}
|
||||
}
|
||||
else if (m_controls.m_brake)
|
||||
else if (m_controls.getBrake())
|
||||
{
|
||||
btVector3 velocity = m_body->getLinearVelocity();
|
||||
if (velocity.length() > -15)
|
||||
@ -2457,9 +2502,9 @@ void Kart::updateFlying()
|
||||
}
|
||||
}
|
||||
|
||||
if (m_controls.m_steer != 0.0f)
|
||||
if (m_controls.getSteer()!= 0.0f)
|
||||
{
|
||||
m_body->applyTorque(btVector3(0.0, m_controls.m_steer * 3500.0f, 0.0));
|
||||
m_body->applyTorque(btVector3(0.0, m_controls.getSteer()*3500.0f, 0.0));
|
||||
}
|
||||
|
||||
// dampen any roll while flying, makes the kart hard to control
|
||||
@ -2695,7 +2740,7 @@ void Kart::updateGraphics(float dt, const Vec3& offset_xyz,
|
||||
// depending on speed)
|
||||
// --------------------------------------------------------
|
||||
float nitro_frac = 0;
|
||||
if ( (m_controls.m_nitro || m_min_nitro_time > 0.0f) &&
|
||||
if ( (m_controls.getNitro() || m_min_nitro_time > 0.0f) &&
|
||||
isOnGround() && m_collected_energy > 0 )
|
||||
{
|
||||
// fabs(speed) is important, otherwise the negative number will
|
||||
@ -2796,7 +2841,7 @@ void Kart::updateGraphics(float dt, const Vec3& offset_xyz,
|
||||
}
|
||||
#ifdef XX
|
||||
// cheap wheelie effect
|
||||
if (m_controls.m_nitro)
|
||||
if (m_controls.getNitro())
|
||||
{
|
||||
m_node->updateAbsolutePosition();
|
||||
m_kart_model->getWheelNodes()[0]->updateAbsolutePosition();
|
||||
|
@ -28,19 +28,21 @@
|
||||
|
||||
#include "LinearMath/btTransform.h"
|
||||
|
||||
#include "items/powerup.hpp"
|
||||
#include "graphics/render_info.hpp"
|
||||
#include "items/powerup_manager.hpp" // For PowerupType
|
||||
#include "karts/abstract_kart.hpp"
|
||||
#include "karts/kart_properties.hpp"
|
||||
#include "utils/no_copy.hpp"
|
||||
|
||||
class btKart;
|
||||
|
||||
class Attachment;
|
||||
class Controller;
|
||||
class Item;
|
||||
class AbstractKartAnimation;
|
||||
class Attachment;
|
||||
class btKart;
|
||||
class btUprightConstraint;
|
||||
class Controller;
|
||||
class HitEffect;
|
||||
class Item;
|
||||
class KartGFX;
|
||||
class KartRewinder;
|
||||
class MaxSpeed;
|
||||
class ParticleEmitter;
|
||||
class ParticleKind;
|
||||
@ -52,8 +54,6 @@ class SlipStream;
|
||||
class Stars;
|
||||
class TerrainInfo;
|
||||
|
||||
enum KartRenderType: unsigned int;
|
||||
|
||||
/** The main kart class. All type of karts are of this object, but with
|
||||
* different controllers. The controllers are what turn a kart into a
|
||||
* player kart (i.e. the controller handle input), or an AI kart (the
|
||||
@ -77,7 +77,7 @@ protected:
|
||||
/** Is time flying activated */
|
||||
bool m_is_jumping;
|
||||
|
||||
private:
|
||||
protected:
|
||||
/** Handles speed increase and capping due to powerup, terrain, ... */
|
||||
MaxSpeed *m_max_speed;
|
||||
|
||||
@ -198,7 +198,11 @@ private:
|
||||
/** When a kart has its view blocked by the plunger, this variable will be
|
||||
* > 0 the number it contains is the time left before removing plunger. */
|
||||
float m_view_blocked_by_plunger;
|
||||
/** The current speed (i.e. length of velocity vector) of this kart. */
|
||||
float m_speed;
|
||||
/** For camera handling an exponentially smoothened value is used, which
|
||||
* reduces stuttering of the camera. */
|
||||
float m_smoothed_speed;
|
||||
|
||||
std::vector<SFXBase*> m_custom_sounds;
|
||||
SFXBase *m_beep_sound;
|
||||
@ -225,6 +229,7 @@ private:
|
||||
void updateSliding();
|
||||
void updateEnginePowerAndBrakes(float dt);
|
||||
void updateEngineSFX();
|
||||
void updateSpeed();
|
||||
void updateNitro(float dt);
|
||||
float getActualWheelForce();
|
||||
void playCrashSFX(const Material* m, AbstractKart *k);
|
||||
@ -234,7 +239,7 @@ public:
|
||||
Kart(const std::string& ident, unsigned int world_kart_id,
|
||||
int position, const btTransform& init_transform,
|
||||
PerPlayerDifficulty difficulty,
|
||||
KartRenderType krt);
|
||||
KartRenderType krt = KRT_DEFAULT);
|
||||
virtual ~Kart();
|
||||
virtual void init(RaceManager::KartType type);
|
||||
virtual void kartIsInRestNow();
|
||||
@ -364,6 +369,9 @@ public:
|
||||
/** Returns the speed of the kart in meters/second. */
|
||||
virtual float getSpeed() const {return m_speed; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the speed of the kart in meters/second. */
|
||||
virtual float getSmoothedSpeed() const { return m_smoothed_speed; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** This is used on the client side only to set the speed of the kart
|
||||
* from the server information. */
|
||||
virtual void setSpeed(float s) {m_speed = s; }
|
||||
|
@ -324,7 +324,7 @@ void KartGFX::updateTerrain(const ParticleKind *pk)
|
||||
bool on_ground = m_kart->isOnGround() &&
|
||||
m_kart->getSkidding()->getGraphicalJumpOffset()==0;
|
||||
if (skidding > 1.0f && on_ground)
|
||||
rate = fabsf(m_kart->getControls().m_steer) > 0.8 ? skidding - 1 : 0;
|
||||
rate = fabsf(m_kart->getControls().getSteer()) > 0.8 ? skidding - 1 : 0;
|
||||
else if (speed >= 0.5f && on_ground)
|
||||
rate = speed/m_kart->getKartProperties()->getEngineMaxSpeed();
|
||||
else
|
||||
|
@ -926,11 +926,10 @@ void KartModel::update(float dt, float distance, float steer, float speed,
|
||||
m_kart->getKartProperties()->getSpeedWeightedObjectProperties().value_name
|
||||
|
||||
// Animation strength
|
||||
float strength = 1.0f;
|
||||
const float strength_factor = GET_VALUE(obj, m_strength_factor);
|
||||
if (strength_factor >= 0.0f)
|
||||
{
|
||||
strength = speed * strength_factor;
|
||||
float strength = speed * strength_factor;
|
||||
btClamp<float>(strength, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
|
162
src/karts/kart_rewinder.cpp
Normal file
162
src/karts/kart_rewinder.cpp
Normal file
@ -0,0 +1,162 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2013 Joerg Henrichs
|
||||
//
|
||||
// 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 "karts/kart_rewinder.hpp"
|
||||
|
||||
#include "items/attachment.hpp"
|
||||
#include "items/powerup.hpp"
|
||||
#include "karts/abstract_kart.hpp"
|
||||
#include "karts/max_speed.hpp"
|
||||
#include "karts/skidding.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "network/rewind_manager.hpp"
|
||||
#include "network/network_string.hpp"
|
||||
#include "physics/btKart.hpp"
|
||||
#include "utils/vec3.hpp"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
KartRewinder::KartRewinder(const std::string& ident,unsigned int world_kart_id,
|
||||
int position, const btTransform& init_transform,
|
||||
PerPlayerDifficulty difficulty,
|
||||
KartRenderType krt)
|
||||
: Rewinder(/*can_be_destroyed*/ false)
|
||||
, Kart(ident, world_kart_id, position, init_transform, difficulty,
|
||||
krt)
|
||||
{
|
||||
} // KartRewinder
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Resets status in case of a resetart.
|
||||
*/
|
||||
void KartRewinder::reset()
|
||||
{
|
||||
Kart::reset();
|
||||
Rewinder::reset();
|
||||
} // reset
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Saves all state information for a kart in a memory buffer. The memory
|
||||
* is allocated here and the address returned. It will then be managed
|
||||
* by the RewindManager. The size is used to keep track of memory usage
|
||||
* for rewinding.
|
||||
* \param[out] buffer Address of the memory buffer.
|
||||
* \returns Size of allocated memory, or -1 in case of an error.
|
||||
*/
|
||||
BareNetworkString* KartRewinder::saveState() const
|
||||
{
|
||||
const int MEMSIZE = 13*sizeof(float) + 9+3;
|
||||
|
||||
BareNetworkString *buffer = new BareNetworkString(MEMSIZE);
|
||||
const btRigidBody *body = getBody();
|
||||
|
||||
// 1) Physics values: transform and velocities
|
||||
// -------------------------------------------
|
||||
const btTransform &t = body->getWorldTransform();
|
||||
buffer->add(t.getOrigin());
|
||||
btQuaternion q = t.getRotation();
|
||||
buffer->add(q);
|
||||
buffer->add(body->getLinearVelocity());
|
||||
buffer->add(body->getAngularVelocity());
|
||||
buffer->addUInt8(m_has_started); // necessary for startup speed boost
|
||||
buffer->addFloat(m_vehicle->getInstantSpeedIncrease());
|
||||
|
||||
// 2) Steering and other player controls
|
||||
// -------------------------------------
|
||||
getControls().copyToBuffer(buffer);
|
||||
|
||||
// 3) Attachment
|
||||
// -------------
|
||||
getAttachment()->saveState(buffer);
|
||||
|
||||
// 4) Powerup
|
||||
// ----------
|
||||
getPowerup()->saveState(buffer);
|
||||
|
||||
// 5) Max speed info
|
||||
// ------------------
|
||||
m_max_speed->saveState(buffer);
|
||||
|
||||
// 6) Skidding
|
||||
// -----------
|
||||
m_skidding->saveState(buffer);
|
||||
|
||||
return buffer;
|
||||
} // saveState
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Actually rewind to the specified state. */
|
||||
void KartRewinder::rewindToState(BareNetworkString *buffer)
|
||||
{
|
||||
buffer->reset(); // make sure the buffer is read from the beginning
|
||||
|
||||
// 1) Physics values: transform and velocities
|
||||
// -------------------------------------------
|
||||
btTransform t;
|
||||
t.setOrigin(buffer->getVec3());
|
||||
t.setRotation(buffer->getQuat());
|
||||
btRigidBody *body = getBody();
|
||||
body->setLinearVelocity(buffer->getVec3());
|
||||
body->setAngularVelocity(buffer->getVec3());
|
||||
// This function also reads the velocity, so it must be called
|
||||
// after the velocities are set
|
||||
body->proceedToTransform(t);
|
||||
// Update kart transform in case that there are access to its value
|
||||
// before Moveable::update() is called (which updates the transform)
|
||||
setTrans(t);
|
||||
m_has_started = buffer->getUInt8()!=0; // necessary for startup speed boost
|
||||
m_vehicle->instantSpeedIncreaseTo(buffer->getFloat());
|
||||
|
||||
// 2) Steering and other controls
|
||||
// ------------------------------
|
||||
getControls().setFromBuffer(buffer);
|
||||
|
||||
// 3) Attachment
|
||||
// -------------
|
||||
getAttachment()->rewindTo(buffer);
|
||||
|
||||
// 4) Powerup
|
||||
// ----------
|
||||
getPowerup()->rewindTo(buffer);
|
||||
|
||||
// 5) Max speed info
|
||||
// ------------------
|
||||
m_max_speed->rewindTo(buffer);
|
||||
m_max_speed->update(0);
|
||||
|
||||
// 6) Skidding
|
||||
// -----------
|
||||
m_skidding->rewindTo(buffer);
|
||||
return;
|
||||
} // rewindToState
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Called once a frame. It will add a new kart control event to the rewind
|
||||
* manager if any control values have changed.
|
||||
*/
|
||||
void KartRewinder::update(float dt)
|
||||
{
|
||||
Kart::update(dt);
|
||||
} // update
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void KartRewinder::rewindToEvent(BareNetworkString *buffer)
|
||||
{
|
||||
}; // rewindToEvent
|
||||
|
||||
|
66
src/karts/kart_rewinder.hpp
Normal file
66
src/karts/kart_rewinder.hpp
Normal file
@ -0,0 +1,66 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2013 Joerg Henrichs
|
||||
//
|
||||
// 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.
|
||||
|
||||
#ifndef HEADER_KART_REWINDER_HPP
|
||||
#define HEADER_KART_REWINDER_HPP
|
||||
|
||||
#include "graphics/render_info.hpp"
|
||||
#include "karts/kart.hpp"
|
||||
#include "network/rewinder.hpp"
|
||||
#include "utils/cpp2011.hpp"
|
||||
|
||||
class AbstractKart;
|
||||
class BareNetworkString;
|
||||
|
||||
class KartRewinder : public Rewinder, public Kart
|
||||
{
|
||||
private:
|
||||
|
||||
// Flags to indicate the different event types
|
||||
enum { EVENT_CONTROL = 0x01,
|
||||
EVENT_ATTACH = 0x02 };
|
||||
public:
|
||||
KartRewinder(const std::string& ident,
|
||||
unsigned int world_kart_id,
|
||||
int position, const btTransform& init_transform,
|
||||
PerPlayerDifficulty difficulty,
|
||||
KartRenderType krt = KRT_DEFAULT);
|
||||
virtual ~KartRewinder() {};
|
||||
virtual BareNetworkString* saveState() const;
|
||||
void reset();
|
||||
virtual void rewindToState(BareNetworkString *p) OVERRIDE;
|
||||
virtual void rewindToEvent(BareNetworkString *p) OVERRIDE;
|
||||
virtual void update(float dt);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
virtual void undoState(BareNetworkString *p) OVERRIDE
|
||||
{
|
||||
}; // undoState
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
virtual void undoEvent(BareNetworkString *p) OVERRIDE
|
||||
{
|
||||
}; // undoEvent
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
}; // Rewinder
|
||||
#endif
|
||||
|
@ -62,11 +62,9 @@ void KartWithStats::reset()
|
||||
void KartWithStats::update(float dt)
|
||||
{
|
||||
Kart::update(dt);
|
||||
if(getSpeed()>m_top_speed) m_top_speed = getSpeed();
|
||||
if(getControls().m_skid)
|
||||
m_skidding_time += dt;
|
||||
if(getControls().m_brake)
|
||||
m_brake_count ++;
|
||||
if(getSpeed()>m_top_speed ) m_top_speed = getSpeed();
|
||||
if(getControls().getSkidControl()) m_skidding_time += dt;
|
||||
if(getControls().getBrake() ) m_brake_count ++;
|
||||
LinearWorld *world = dynamic_cast<LinearWorld*>(World::getWorld());
|
||||
if(world && !world->isOnRoad(getWorldKartId()))
|
||||
m_off_track_count ++;
|
||||
|
@ -135,8 +135,7 @@ void MaxSpeed::instantSpeedIncrease(unsigned int category,
|
||||
|
||||
m_kart->getVehicle()->instantSpeedIncreaseTo(speed);
|
||||
|
||||
}
|
||||
// instantSpeedIncrease
|
||||
} // instantSpeedIncrease
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Handles the update of speed increase objects. The m_duration variable
|
||||
@ -161,6 +160,34 @@ void MaxSpeed::SpeedIncrease::update(float dt)
|
||||
m_current_speedup -= dt*m_max_add_speed/m_fade_out_time;
|
||||
} // SpeedIncrease::update
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void MaxSpeed::SpeedIncrease::saveState(BareNetworkString *buffer) const
|
||||
{
|
||||
buffer->addFloat(m_max_add_speed);
|
||||
buffer->addFloat(m_duration);
|
||||
buffer->addFloat(m_fade_out_time);
|
||||
buffer->addFloat(m_current_speedup);
|
||||
buffer->addFloat(m_engine_force);
|
||||
} // saveState
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void MaxSpeed::SpeedIncrease::rewindTo(BareNetworkString *buffer,
|
||||
bool is_active)
|
||||
{
|
||||
if(is_active)
|
||||
{
|
||||
m_max_add_speed = buffer->getFloat();
|
||||
m_duration = buffer->getFloat();
|
||||
m_fade_out_time = buffer->getFloat();
|
||||
m_current_speedup = buffer->getFloat();
|
||||
m_engine_force = buffer->getFloat();
|
||||
}
|
||||
else // make sure to disable this category
|
||||
{
|
||||
reset();
|
||||
}
|
||||
} // restoreState
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Defines a slowdown, which is in fraction of top speed.
|
||||
* \param category The category for which the speed is increased.
|
||||
@ -210,6 +237,38 @@ void MaxSpeed::SpeedDecrease::update(float dt)
|
||||
m_current_fraction = m_max_speed_fraction;
|
||||
} // SpeedDecrease::update
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Saves the state of an (active) speed decrease category. It is not called
|
||||
* if the speed decrease is not active.
|
||||
* \param buffer Buffer which will store the state information.
|
||||
*/
|
||||
void MaxSpeed::SpeedDecrease::saveState(BareNetworkString *buffer) const
|
||||
{
|
||||
buffer->addFloat(m_max_speed_fraction);
|
||||
buffer->addFloat(m_fade_in_time);
|
||||
buffer->addFloat(m_current_fraction);
|
||||
buffer->addFloat(m_duration);
|
||||
} // saveState
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Restores a previously saved state for an active speed decrease category.
|
||||
*/
|
||||
void MaxSpeed::SpeedDecrease::rewindTo(BareNetworkString *buffer,
|
||||
bool is_active)
|
||||
{
|
||||
if(is_active)
|
||||
{
|
||||
m_max_speed_fraction = buffer->getFloat();
|
||||
m_fade_in_time = buffer->getFloat();
|
||||
m_current_fraction = buffer->getFloat();
|
||||
m_duration = buffer->getFloat();
|
||||
}
|
||||
else // make sure it is not active
|
||||
{
|
||||
reset();
|
||||
}
|
||||
} // restoreState
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Returns how much increased speed time is left over in the given category.
|
||||
* \param category Which category to report on.
|
||||
@ -267,3 +326,70 @@ void MaxSpeed::update(float dt)
|
||||
} // update
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Saves the speed data in a network string for rewind.
|
||||
* \param buffer Pointer to the network string to store the data.
|
||||
*/
|
||||
void MaxSpeed::saveState(BareNetworkString *buffer) const
|
||||
{
|
||||
// Save the slowdown states
|
||||
// ------------------------
|
||||
// Get the bit pattern of all active slowdowns
|
||||
uint8_t active_slowdown = 0;
|
||||
for(unsigned int i=MS_DECREASE_MIN, b=1; i<MS_DECREASE_MAX; i++, b <<=1)
|
||||
{
|
||||
if (m_speed_decrease[i].isActive())
|
||||
active_slowdown |= b;
|
||||
}
|
||||
buffer->addUInt8(active_slowdown);
|
||||
|
||||
for(unsigned int i=MS_DECREASE_MIN, b=1; i<MS_DECREASE_MAX; i++, b <<= 1)
|
||||
{
|
||||
if (active_slowdown & b)
|
||||
m_speed_decrease->saveState(buffer);
|
||||
}
|
||||
|
||||
// Now save the speedup state
|
||||
// --------------------------
|
||||
// Get the bit pattern of all active speedups
|
||||
uint8_t active_speedups = 0;
|
||||
for(unsigned int i=MS_INCREASE_MIN, b=1; i<MS_INCREASE_MAX; i++, b <<= 1)
|
||||
{
|
||||
if(m_speed_increase[i].isActive())
|
||||
active_speedups |= b;
|
||||
}
|
||||
buffer->addUInt8(active_speedups);
|
||||
for(unsigned int i=MS_INCREASE_MIN, b=1; i<MS_INCREASE_MAX; i++, b <<= 1)
|
||||
{
|
||||
if(active_speedups & b)
|
||||
m_speed_increase[i].saveState(buffer);
|
||||
}
|
||||
|
||||
} // saveState
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Restore a saved state.
|
||||
* \param buffer Saved state.
|
||||
*/
|
||||
void MaxSpeed::rewindTo(BareNetworkString *buffer)
|
||||
{
|
||||
// Restore the slowdown states
|
||||
// ---------------------------
|
||||
// Get the bit pattern of all active slowdowns
|
||||
uint8_t active_slowdown = buffer->getUInt8();
|
||||
|
||||
for(unsigned int i=MS_DECREASE_MIN, b=1; i<MS_DECREASE_MAX; i++, b <<= 1)
|
||||
{
|
||||
m_speed_decrease->rewindTo(buffer, (active_slowdown & b) == b);
|
||||
}
|
||||
|
||||
// Restore the speedup state
|
||||
// --------------------------
|
||||
// Get the bit pattern of all active speedups
|
||||
uint8_t active_speedups = buffer->getUInt8();
|
||||
for(unsigned int i=MS_INCREASE_MIN, b=1; i<MS_INCREASE_MAX; i++, b <<= 1)
|
||||
{
|
||||
m_speed_increase[i].rewindTo(buffer, (active_speedups & b) == b);
|
||||
}
|
||||
|
||||
} // rewindoTo
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
/** \defgroup karts */
|
||||
|
||||
class AbstractKart;
|
||||
class BareNetworkString;
|
||||
|
||||
class MaxSpeed
|
||||
{
|
||||
@ -81,18 +82,27 @@ private:
|
||||
/** The constructor initialised the values with a no-increase
|
||||
* entry, i.e. an entry that does affect top speed at all. */
|
||||
SpeedIncrease()
|
||||
{
|
||||
reset();
|
||||
} // SpeedIncrease
|
||||
// --------------------------------------------------------------------
|
||||
/** Resets this increase category to be not active. */
|
||||
void reset()
|
||||
{
|
||||
m_max_add_speed = 0;
|
||||
m_duration = -9999999;
|
||||
m_fade_out_time = 0;
|
||||
m_current_speedup = 0;
|
||||
m_engine_force = 0;
|
||||
} // SpeedIncrease
|
||||
} // reset
|
||||
// --------------------------------------------------------------------
|
||||
void update(float dt);
|
||||
/** Returns the current speedup for this category. */
|
||||
void saveState(BareNetworkString *buffer) const;
|
||||
void rewindTo(BareNetworkString *buffer, bool is_active);
|
||||
// --------------------------------------------------------------------
|
||||
/** Returns the current speedup for this category. */
|
||||
float getSpeedIncrease() const {return m_current_speedup;}
|
||||
// --------------------------------------------------------------------
|
||||
/** Returns the remaining time till the fade out time starts.
|
||||
* Note that this function will return a negative value if
|
||||
* the fade_out time has started or this speed increase has
|
||||
@ -103,7 +113,10 @@ private:
|
||||
float getEngineForce() const
|
||||
{
|
||||
return m_duration > 0 ? m_engine_force : 0;
|
||||
}
|
||||
} // getEngineForce
|
||||
// --------------------------------------------------------------------
|
||||
/** Returns if this speed increase is active atm. */
|
||||
bool isActive() const { return m_duration > -m_fade_out_time; }
|
||||
}; // SpeedIncrease
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
@ -126,17 +139,30 @@ private:
|
||||
/** The constructor initialises the data with data that won't
|
||||
* affect top speed at all. */
|
||||
SpeedDecrease()
|
||||
{
|
||||
reset();
|
||||
} // SpeedDecrease
|
||||
// --------------------------------------------------------------------
|
||||
/** Resets the state to be inactive. */
|
||||
void reset()
|
||||
{
|
||||
m_max_speed_fraction = 1.0f;
|
||||
m_fade_in_time = 0.0f;
|
||||
m_current_fraction = 1.0f;
|
||||
m_duration = -1.0f;
|
||||
} // SpeedDecrease
|
||||
m_duration = 0.0f;
|
||||
} //reset
|
||||
// --------------------------------------------------------------------
|
||||
void update(float dt);
|
||||
void saveState(BareNetworkString *buffer) const;
|
||||
void rewindTo(BareNetworkString *buffer, bool is_active);
|
||||
// --------------------------------------------------------------------
|
||||
/** Returns the current slowdown fracftion, taking a 'fade in'
|
||||
* into account. */
|
||||
float getSlowdownFraction() const {return m_current_fraction;}
|
||||
// --------------------------------------------------------------------
|
||||
/** Returns if this speed decrease is active atm. A duration of
|
||||
* -1 indicates an ongoing effect. */
|
||||
bool isActive() const { return m_duration > 0 || m_duration <= -1.0f; }
|
||||
}; // SpeedDecrease
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
@ -164,6 +190,8 @@ public:
|
||||
float getSpeedIncreaseTimeLeft(unsigned int category);
|
||||
void update(float dt);
|
||||
void reset();
|
||||
void saveState(BareNetworkString *buffer) const;
|
||||
void rewindTo(BareNetworkString *buffer);
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets the minimum speed a kart should have. This is used to guarantee
|
||||
* that e.g. zippers on ramps will always fast enough for the karts to
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "karts/max_speed.hpp"
|
||||
#include "karts/controller/controller.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "network/network_string.hpp"
|
||||
#include "physics/btKart.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
#include "utils/log.hpp"
|
||||
@ -77,7 +78,7 @@ void Skidding::reset()
|
||||
m_kart->getKartGFX()->setCreationRateAbsolute(KartGFX::KGFX_SKIDL, 0);
|
||||
m_kart->getKartGFX()->setCreationRateAbsolute(KartGFX::KGFX_SKIDR, 0);
|
||||
m_kart->getKartGFX()->updateSkidLight(0);
|
||||
m_kart->getControls().m_skid = KartControl::SC_NONE;
|
||||
m_kart->getControls().setSkidControl(KartControl::SC_NONE);
|
||||
|
||||
btVector3 rot(0, 0, 0);
|
||||
// Only access the vehicle if the kart is not a ghost
|
||||
@ -85,6 +86,36 @@ void Skidding::reset()
|
||||
m_kart->getVehicle()->setTimedRotation(0, rot);
|
||||
} // reset
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Save the skidding state of a kart. It only saves the important physics
|
||||
* values, not visual only values like m_visual_rotation, m_gfx_jump_offset,
|
||||
* m_remaining_jump_time and m_jump_speed. Similarly m_real_steering is output
|
||||
* of updateRewind() and will be recomputed every frame when update() is called,
|
||||
* and similart m_skid_bonus_ready
|
||||
* \param buffer Buffer for the state information.
|
||||
*/
|
||||
void Skidding::saveState(BareNetworkString *buffer)
|
||||
{
|
||||
buffer->addUInt8(m_skid_state);
|
||||
if(m_skid_state == SKID_NONE)
|
||||
return;
|
||||
buffer->addFloat(m_skid_time);
|
||||
buffer->addFloat(m_skid_factor);
|
||||
} // saveState
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Restores the skidding state of a kart.
|
||||
* \param buffer Buffer with state information.
|
||||
*/
|
||||
void Skidding::rewindTo(BareNetworkString *buffer)
|
||||
{
|
||||
m_skid_state = (SkidState)buffer->getUInt8();
|
||||
if(m_skid_state == SKID_NONE)
|
||||
return;
|
||||
m_skid_time = buffer->getFloat();
|
||||
m_skid_factor = buffer->getFloat();
|
||||
} // rewindTo
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Computes the actual steering fraction to be used in the physics, and
|
||||
* stores it in m_real_skidding. This is later used by kart to set the
|
||||
@ -92,8 +123,10 @@ void Skidding::reset()
|
||||
* kart skids either left or right, the steering fraction is bound by
|
||||
* reduce-turn-min and reduce-turn-max.
|
||||
*/
|
||||
void Skidding::updateSteering(float steer, float dt)
|
||||
float Skidding::updateSteering(float steer, float dt)
|
||||
{
|
||||
float steer_result;
|
||||
|
||||
const KartProperties *kp = m_kart->getKartProperties();
|
||||
|
||||
switch(m_skid_state)
|
||||
@ -101,7 +134,7 @@ void Skidding::updateSteering(float steer, float dt)
|
||||
case SKID_SHOW_GFX_LEFT:
|
||||
case SKID_SHOW_GFX_RIGHT:
|
||||
case SKID_NONE:
|
||||
m_real_steering = steer;
|
||||
steer_result = steer;
|
||||
if (m_skid_time < kp->getSkidVisualTime() && m_skid_time > 0)
|
||||
{
|
||||
float f = m_visual_rotation - m_visual_rotation*dt/m_skid_time;
|
||||
@ -115,7 +148,7 @@ void Skidding::updateSteering(float steer, float dt)
|
||||
}
|
||||
break;
|
||||
case SKID_BREAK:
|
||||
m_real_steering = steer;
|
||||
steer_result = steer;
|
||||
if (m_visual_rotation > 0.1f) m_visual_rotation -= 0.1f;
|
||||
else if (m_visual_rotation < -0.1f) m_visual_rotation += 0.1f;
|
||||
else
|
||||
@ -126,33 +159,33 @@ void Skidding::updateSteering(float steer, float dt)
|
||||
case SKID_ACCUMULATE_RIGHT:
|
||||
{
|
||||
float f = (1.0f+steer)*0.5f; // map [-1,1] --> [0, 1]
|
||||
m_real_steering = kp->getSkidReduceTurnMin()
|
||||
steer_result = kp->getSkidReduceTurnMin()
|
||||
+ m_skid_reduce_turn_delta * f;
|
||||
if(m_skid_time < kp->getSkidVisualTime())
|
||||
m_visual_rotation = kp->getSkidVisual()
|
||||
* m_real_steering * m_skid_time
|
||||
* steer_result * m_skid_time
|
||||
/ kp->getSkidVisualTime();
|
||||
else
|
||||
m_visual_rotation = kp->getSkidVisual() * m_real_steering;
|
||||
m_visual_rotation = kp->getSkidVisual() * steer_result;
|
||||
break;
|
||||
}
|
||||
} // SKID_ACCUMULATE_RIGHT
|
||||
case SKID_ACCUMULATE_LEFT:
|
||||
{
|
||||
float f = (-1.0f+steer)*0.5f; // map [-1,1] --> [-1, 0]
|
||||
m_real_steering = -kp->getSkidReduceTurnMin()
|
||||
steer_result = -kp->getSkidReduceTurnMin()
|
||||
+ m_skid_reduce_turn_delta * f;
|
||||
if(m_skid_time < kp->getSkidVisualTime())
|
||||
m_visual_rotation = kp->getSkidVisual()
|
||||
* m_real_steering * m_skid_time
|
||||
* steer_result * m_skid_time
|
||||
/ kp->getSkidVisualTime();
|
||||
else
|
||||
m_visual_rotation = kp->getSkidVisual() * m_real_steering;
|
||||
m_visual_rotation = kp->getSkidVisual() * steer_result;
|
||||
break;
|
||||
}
|
||||
|
||||
} // case SKID_ACCUMULATE_LEFT
|
||||
|
||||
} // switch m_skid_state
|
||||
|
||||
return steer_result;
|
||||
} // updateSteering
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -279,7 +312,7 @@ void Skidding::update(float dt, bool is_on_ground,
|
||||
// a potential bonus. Also the rotation of the physical body to
|
||||
// be in synch with the graphical kart is started (which is
|
||||
// independently handled in the kart physics).
|
||||
// SKID_SHOW_GFX_{LEFT<RIGHT}
|
||||
// SKID_SHOW_GFX_{LEFT,RIGHT}
|
||||
// Shows the skidding gfx while the bonus is available.
|
||||
// FIXME: what should we do if skid key is pressed while still in
|
||||
// SKID_SHOW_GFX??? Adjusting the body rotation is difficult.
|
||||
@ -318,21 +351,17 @@ void Skidding::update(float dt, bool is_on_ground,
|
||||
|
||||
#ifdef SKID_DEBUG
|
||||
#define SPEED 20.0f
|
||||
updateSteering(steering, dt);
|
||||
m_real_steering = updateSteering(steering, dt);
|
||||
m_actual_curve->clear();
|
||||
m_actual_curve->setVisible(true);
|
||||
m_predicted_curve->clear();
|
||||
m_predicted_curve->setVisible(true);
|
||||
m_predicted_curve->setPosition(m_kart->getXYZ());
|
||||
m_predicted_curve->setHeading(m_kart->getHeading());
|
||||
float angle = kp
|
||||
->getMaxSteerAngle(m_kart->getSpeed())
|
||||
* fabsf(getSteeringFraction());
|
||||
angle = kp
|
||||
->getMaxSteerAngle(SPEED)
|
||||
float angle = kp->getMaxSteerAngle(SPEED)
|
||||
* fabsf(getSteeringFraction());
|
||||
float r = kp->getWheelBase()
|
||||
/ asin(angle)*1.0f;
|
||||
/ asin(angle)*1.0f;
|
||||
|
||||
const int num_steps = 50;
|
||||
|
||||
@ -444,7 +473,8 @@ void Skidding::update(float dt, bool is_on_ground,
|
||||
m_skid_state = SKID_NONE;
|
||||
}
|
||||
} // switch
|
||||
updateSteering(steering, dt);
|
||||
|
||||
m_real_steering = updateSteering(steering, dt);
|
||||
} // update
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "utils/leak_check.hpp"
|
||||
#include "utils/no_copy.hpp"
|
||||
|
||||
class BareNetworkString;
|
||||
class Kart;
|
||||
class ShowCurve;
|
||||
|
||||
@ -98,13 +99,15 @@ private:
|
||||
|
||||
unsigned int getSkidBonus(float *bonus_time, float *bonus_speed,
|
||||
float *bonus_force) const;
|
||||
void updateSteering(float steer, float dt);
|
||||
float updateSteering(float steer, float dt);
|
||||
public:
|
||||
Skidding(Kart *kart);
|
||||
~Skidding();
|
||||
void reset();
|
||||
void update(float dt, bool is_on_ground, float steer,
|
||||
KartControl::SkidControl skidding);
|
||||
void saveState(BareNetworkString *buffer);
|
||||
void rewindTo(BareNetworkString *buffer);
|
||||
// ------------------------------------------------------------------------
|
||||
/** Determines how much the graphics model of the kart should be rotated
|
||||
* additionally (for skidding), depending on how long the kart has been
|
||||
|
16
src/main.cpp
16
src/main.cpp
@ -179,6 +179,7 @@
|
||||
#include "modes/profile_world.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
#include "network/network_string.hpp"
|
||||
#include "network/rewind_manager.hpp"
|
||||
#include "network/servers_manager.hpp"
|
||||
#include "network/stk_host.hpp"
|
||||
#include "online/profile_manager.hpp"
|
||||
@ -395,9 +396,11 @@ void handleXmasMode()
|
||||
*/
|
||||
bool isEasterMode(int day, int month, int year, int before_after_days)
|
||||
{
|
||||
switch (UserConfigParams::m_easter_ear_mode)
|
||||
{
|
||||
case 0:
|
||||
if (UserConfigParams::m_easter_ear_mode == 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (UserConfigParams::m_easter_ear_mode == 0)
|
||||
{
|
||||
// Compute Easter date, based on wikipedia formula
|
||||
// http://en.wikipedia.org/wiki/Computus
|
||||
@ -429,12 +432,9 @@ bool isEasterMode(int day, int month, int year, int before_after_days)
|
||||
}
|
||||
return (month > easter_start_month || (month == easter_start_month && day >= easter_start_day)) &&
|
||||
(month < easter_end_month || (month == easter_end_month && day <= easter_end_day));
|
||||
break;
|
||||
}
|
||||
case 1: return true; break;
|
||||
default: return false; break;
|
||||
} // switch m_xmas_mode
|
||||
|
||||
return false;
|
||||
} // isEasterMode(day, month, year, before_after_days)
|
||||
|
||||
// ============================================================================
|
||||
@ -880,6 +880,8 @@ int handleCmdLine()
|
||||
AIBaseController::setTestAI(n);
|
||||
if (CommandLine::has("--fps-debug"))
|
||||
UserConfigParams::m_fps_debug = true;
|
||||
if (CommandLine::has("--rewind") )
|
||||
RewindManager::setEnable(true);
|
||||
if(CommandLine::has("--soccer-ai-stats"))
|
||||
{
|
||||
UserConfigParams::m_arena_ai_stats=true;
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "network/race_event_manager.hpp"
|
||||
#include "network/stk_host.hpp"
|
||||
#include "online/request_manager.hpp"
|
||||
#include "race/history.hpp"
|
||||
#include "race/race_manager.hpp"
|
||||
#include "states_screens/state_manager.hpp"
|
||||
#include "utils/profiler.hpp"
|
||||
@ -61,6 +62,15 @@ MainLoop::~MainLoop()
|
||||
*/
|
||||
float MainLoop::getLimitedDt()
|
||||
{
|
||||
float dt = 0;
|
||||
// If we are doing a replay, use the dt from the history file
|
||||
if (World::getWorld() && history->replayHistory() )
|
||||
{
|
||||
dt = history->updateReplayAndGetDT();
|
||||
return dt;
|
||||
}
|
||||
|
||||
|
||||
// In profile mode without graphics, run with a fixed dt of 1/60
|
||||
if ((ProfileWorld::isProfileMode() && ProfileWorld::isNoGraphics()) ||
|
||||
UserConfigParams::m_arena_ai_stats)
|
||||
@ -71,7 +81,6 @@ float MainLoop::getLimitedDt()
|
||||
IrrlichtDevice* device = irr_driver->getDevice();
|
||||
m_prev_time = m_curr_time;
|
||||
|
||||
float dt; // needed outside of the while loop
|
||||
while( 1 )
|
||||
{
|
||||
m_curr_time = device->getTimer()->getRealTime();
|
||||
@ -135,6 +144,72 @@ void MainLoop::updateRace(float dt)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Run the actual main loop.
|
||||
* The sequnce in which various parts of STK are updated is:
|
||||
* - Determine next time step size (`getLimitedDt`). This takes maximum fps
|
||||
* into account (i.e. sleep if the fps would be too high), and will actually
|
||||
* slow down the in-game clock if the fps are too low (if more than 3/60 of
|
||||
* a second have passed, more than 3 physics time steps would be needed,
|
||||
* and physics do at most 3 time steps).
|
||||
* - if a race is taking place (i.e. not only a menu being shown), call
|
||||
* `updateRace()`, which is a thin wrapper around a call to
|
||||
* `World::updateWorld()`:
|
||||
* - Update history manager (which will either set the kart position and/or
|
||||
* controls when replaying, or store the current info for a replay).
|
||||
* This is mostly for debugging only (though available even in release
|
||||
* mode).
|
||||
* - Updates Replays - either storing data when not replaying, or
|
||||
* updating kart positions/control when replaying).
|
||||
* - Calls `WorldStatus::update()`, which updates the race state (e.g.
|
||||
* go from 'ready' to 'set' etc), and clock.
|
||||
* - Updates the physics (`Physics::update()`). This will simulate all
|
||||
* physical objects for the specified time with bullet.
|
||||
* - Updates all karts (`Kart::update()`). Obviously the update function
|
||||
* does a lot more than what is described here, this is only supposed to
|
||||
* be a _very_ high level overview:
|
||||
* - Updates its rewinder (to store potentially changed controls
|
||||
* as events) in `KartRewinder::update()`.
|
||||
* - Calls `Moveable::update()`, which takes the new position from
|
||||
* the physics and saves it (and computes dependent values, like
|
||||
* heading, local velocity).
|
||||
* - Updates its controller. This is either:
|
||||
* - an AI using `SkiddingController::update()` (which then will
|
||||
* compute the new controls), or
|
||||
* - a player controller using `PlayerController::update()`, which will
|
||||
* handle smooth steering (in case of digital input devices steering
|
||||
* is adjusted a bit over time to avoid an instant change from all
|
||||
* left to all right). Input events will be handled when updating
|
||||
* the irrlicht driver later at the end of the main loop.
|
||||
* - Updates kart animation (like rescue, ...) if one is shown atm.
|
||||
* - Update attachments.
|
||||
* - update physics, i.e. taking the current steering and updating
|
||||
* the bullet raycast vehicle with that data. The settings are actually
|
||||
* only used in the next frame when the physics are updated.
|
||||
* - Updates all cameras via `Camera::update()`. The camera position and
|
||||
* rotation is adjusted according to the position etc of the kart (and
|
||||
* special circumstances like rescue, falling).
|
||||
* - Updates all projectiles using the projectile manager. Some of the
|
||||
* projectiles are mostly handled by the physics (e.g. a cake will mainly
|
||||
* check if it's out of bounds), others (like basket ball) do all
|
||||
* their aiming and movement here.
|
||||
* - Updates the rewind manager to store rewind states.
|
||||
* - Updates the music manager.
|
||||
* - Updates the input manager (which only updates internal time, actual
|
||||
* input handling follows late)
|
||||
* - Updates the wiimote manager. This will read the data of all wiimotes
|
||||
* and feed the corresponding events to the irrlicht event system.
|
||||
* - Updates the STK internal gui engine. This updates all widgets, and
|
||||
* e.g. takes care of the rotation of the karts in the KartSelection
|
||||
* screen using the ModelViewWidget.
|
||||
* - Updates STK's irrlicht driver `IrrDriver::update()`:
|
||||
* - Calls Irrlicht's `beginScene()` .
|
||||
* - Renders the scene (several times with different viewport if
|
||||
* split screen is being used)
|
||||
* - Calls `GUIEngine::render()`, which renders all widgets with the
|
||||
* help of Irrlicht's GUIEnvironment (`drawAll()`). This will also
|
||||
* handle all events, i.e. all input is now handled (e.g. steering,
|
||||
* firing etc are all set in the corresponding karts depending on
|
||||
* user input).
|
||||
* - Calls Irrlicht's `endScene()`
|
||||
*/
|
||||
void MainLoop::run()
|
||||
{
|
||||
@ -147,6 +222,11 @@ void MainLoop::run()
|
||||
|
||||
m_prev_time = m_curr_time;
|
||||
float dt = getLimitedDt();
|
||||
// Render the previous frame, and also handle all user input.
|
||||
PROFILER_PUSH_CPU_MARKER("IrrDriver update", 0x00, 0x00, 0x7F);
|
||||
irr_driver->update(dt);
|
||||
PROFILER_POP_CPU_MARKER();
|
||||
|
||||
|
||||
if (World::getWorld()) // race is active if world exists
|
||||
{
|
||||
@ -172,10 +252,6 @@ void MainLoop::run()
|
||||
GUIEngine::update(dt);
|
||||
PROFILER_POP_CPU_MARKER();
|
||||
|
||||
PROFILER_PUSH_CPU_MARKER("IrrDriver update", 0x00, 0x00, 0x7F);
|
||||
irr_driver->update(dt);
|
||||
PROFILER_POP_CPU_MARKER();
|
||||
|
||||
// Update sfx and music after graphics, so that graphics code
|
||||
// can use as many threads as possible without interfering
|
||||
// with audio
|
||||
@ -209,6 +285,10 @@ void MainLoop::run()
|
||||
PROFILER_POP_CPU_MARKER();
|
||||
}
|
||||
|
||||
// Update world time if world exists
|
||||
if (World::getWorld())
|
||||
World::getWorld()->updateTime(dt);
|
||||
|
||||
PROFILER_POP_CPU_MARKER();
|
||||
PROFILER_SYNC_FRAME();
|
||||
} // while !m_abort
|
||||
|
@ -42,10 +42,12 @@
|
||||
#include "karts/controller/network_player_controller.hpp"
|
||||
#include "karts/kart.hpp"
|
||||
#include "karts/kart_properties_manager.hpp"
|
||||
#include "karts/kart_rewinder.hpp"
|
||||
#include "modes/overworld.hpp"
|
||||
#include "modes/profile_world.hpp"
|
||||
#include "modes/soccer_world.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
#include "network/rewind_manager.hpp"
|
||||
#include "physics/btKart.hpp"
|
||||
#include "physics/physics.hpp"
|
||||
#include "physics/triangle_mesh.hpp"
|
||||
@ -163,9 +165,11 @@ void World::init()
|
||||
// constructor is called, so the wrong race gui would be created.
|
||||
createRaceGUI();
|
||||
|
||||
RewindManager::create();
|
||||
|
||||
// Grab the track file
|
||||
m_track = track_manager->getTrack(race_manager->getTrackName());
|
||||
m_script_engine = new Scripting::ScriptEngine();
|
||||
m_script_engine = new Scripting::ScriptEngine();
|
||||
if(!m_track)
|
||||
{
|
||||
std::ostringstream msg;
|
||||
@ -238,6 +242,8 @@ void World::init()
|
||||
*/
|
||||
void World::reset()
|
||||
{
|
||||
RewindManager::get()->reset();
|
||||
|
||||
// If m_saved_race_gui is set, it means that the restart was done
|
||||
// when the race result gui was being shown. In this case restore the
|
||||
// race gui (note that the race result gui is cached and so never really
|
||||
@ -335,8 +341,13 @@ AbstractKart *World::createKart(const std::string &kart_ident, int index,
|
||||
|
||||
int position = index+1;
|
||||
btTransform init_pos = getStartTransform(index - gk);
|
||||
AbstractKart *new_kart = new Kart(kart_ident, index, position, init_pos,
|
||||
difficulty, KRT_DEFAULT);
|
||||
AbstractKart *new_kart;
|
||||
if (RewindManager::get()->isEnabled())
|
||||
new_kart = new KartRewinder(kart_ident, index, position, init_pos,
|
||||
difficulty);
|
||||
else
|
||||
new_kart = new Kart(kart_ident, index, position, init_pos, difficulty);
|
||||
|
||||
new_kart->init(race_manager->getKartType(index));
|
||||
Controller *controller = NULL;
|
||||
switch(kart_type)
|
||||
@ -415,6 +426,8 @@ Controller* World::loadAIController(AbstractKart *kart)
|
||||
//-----------------------------------------------------------------------------
|
||||
World::~World()
|
||||
{
|
||||
RewindManager::destroy();
|
||||
|
||||
irr_driver->onUnloadWorld();
|
||||
|
||||
// In case that a race is aborted (e.g. track not found) m_track is 0.
|
||||
@ -827,6 +840,11 @@ void World::updateWorld(float dt)
|
||||
getPhase() == IN_GAME_MENU_PHASE )
|
||||
return;
|
||||
|
||||
if (!history->replayHistory())
|
||||
{
|
||||
history->updateSaving(dt); // updating the saved state
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
update(dt);
|
||||
@ -916,7 +934,7 @@ void World::scheduleTutorial()
|
||||
{
|
||||
m_schedule_exit_race = true;
|
||||
m_schedule_tutorial = true;
|
||||
}
|
||||
} // scheduleTutorial
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Updates the physics, all karts, the track, and projectile manager.
|
||||
@ -928,7 +946,6 @@ void World::update(float dt)
|
||||
assert(m_magic_number == 0xB01D6543);
|
||||
#endif
|
||||
|
||||
|
||||
PROFILER_PUSH_CPU_MARKER("World::update()", 0x00, 0x7F, 0x00);
|
||||
|
||||
#if MEASURE_FPS
|
||||
@ -942,19 +959,15 @@ void World::update(float dt)
|
||||
#endif
|
||||
|
||||
PROFILER_PUSH_CPU_MARKER("World::update (sub-updates)", 0x20, 0x7F, 0x00);
|
||||
history->update(dt);
|
||||
if(race_manager->isRecordingRace()) ReplayRecorder::get()->update(dt);
|
||||
if(history->replayHistory()) dt=history->getNextDelta();
|
||||
WorldStatus::update(dt);
|
||||
if (m_script_engine) m_script_engine->update(dt);
|
||||
RewindManager::get()->saveStates();
|
||||
PROFILER_POP_CPU_MARKER();
|
||||
|
||||
if (!history->dontDoPhysics())
|
||||
{
|
||||
m_physics->update(dt);
|
||||
}
|
||||
PROFILER_PUSH_CPU_MARKER("World::update (Kart::upate)", 0x40, 0x7F, 0x00);
|
||||
|
||||
PROFILER_PUSH_CPU_MARKER("World::update (Kart::update)", 0x40, 0x7F, 0x00);
|
||||
// Update all the karts. This in turn will also update the controller,
|
||||
// which causes all AI steering commands set. So in the following
|
||||
// physics update the new steering is taken into account.
|
||||
const int kart_amount = (int)m_karts.size();
|
||||
for (int i = 0 ; i < kart_amount; ++i)
|
||||
{
|
||||
@ -970,6 +983,14 @@ void World::update(float dt)
|
||||
}
|
||||
PROFILER_POP_CPU_MARKER();
|
||||
|
||||
if(race_manager->isRecordingRace()) ReplayRecorder::get()->update(dt);
|
||||
if (m_script_engine) m_script_engine->update(dt);
|
||||
|
||||
if (!history->dontDoPhysics())
|
||||
{
|
||||
m_physics->update(dt);
|
||||
}
|
||||
|
||||
PROFILER_PUSH_CPU_MARKER("World::update (weather)", 0x80, 0x7F, 0x00);
|
||||
if (UserConfigParams::m_graphical_effects && m_weather)
|
||||
{
|
||||
@ -988,6 +1009,17 @@ void World::update(float dt)
|
||||
#endif
|
||||
} // update
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Compute the new time, and set this new time to be used in the rewind
|
||||
* manager.
|
||||
* \param dt Time step size.
|
||||
*/
|
||||
void World::updateTime(const float dt)
|
||||
{
|
||||
WorldStatus::updateTime(dt);
|
||||
RewindManager::get()->setCurrentTime(getTime(), dt);
|
||||
} // updateTime
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Only updates the track. The order in which the various parts of STK are
|
||||
* updated is quite important (i.e. the track can't be updated as part of
|
||||
|
@ -178,7 +178,7 @@ protected:
|
||||
virtual void onGo() OVERRIDE;
|
||||
/** Returns true if the race is over. Must be defined by all modes. */
|
||||
virtual bool isRaceOver() = 0;
|
||||
virtual void update(float dt);
|
||||
virtual void update(float dt) OVERRIDE;
|
||||
virtual void createRaceGUI();
|
||||
void updateTrack(float dt);
|
||||
// ------------------------------------------------------------------------
|
||||
@ -252,9 +252,10 @@ public:
|
||||
// =================
|
||||
virtual void init();
|
||||
virtual void terminateRace() OVERRIDE;
|
||||
virtual void reset();
|
||||
virtual void reset() OVERRIDE;
|
||||
virtual void pause(Phase phase) OVERRIDE;
|
||||
virtual void unpause() OVERRIDE;
|
||||
virtual void updateTime(const float dt) OVERRIDE;
|
||||
virtual void getDefaultCollectibles(int *collectible_type,
|
||||
int *amount );
|
||||
virtual void endRaceEarly() { return; }
|
||||
|
@ -153,10 +153,21 @@ void WorldStatus::terminateRace()
|
||||
} // terminateRace
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Updates all status information, called once per frame.
|
||||
/** Update, called once per frame. Called early on before physics are
|
||||
* updated.
|
||||
* \param dt Time step.
|
||||
*/
|
||||
void WorldStatus::update(float dt)
|
||||
{
|
||||
} // update
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Updates the world time and clock (which might be running backwards), and
|
||||
* all status information, called once per frame at the end of the main
|
||||
* loop.
|
||||
* \param dt Duration of time step.
|
||||
*/
|
||||
void WorldStatus::update(const float dt)
|
||||
void WorldStatus::updateTime(const float dt)
|
||||
{
|
||||
switch (m_phase)
|
||||
{
|
||||
|
@ -122,13 +122,14 @@ public:
|
||||
WorldStatus();
|
||||
virtual ~WorldStatus();
|
||||
|
||||
void reset();
|
||||
void update(const float dt);
|
||||
void setTime(const float time);
|
||||
virtual void reset();
|
||||
virtual void updateTime(const float dt);
|
||||
virtual void update(float dt);
|
||||
virtual void pause(Phase phase);
|
||||
virtual void unpause();
|
||||
virtual void enterRaceOverState();
|
||||
virtual void terminateRace();
|
||||
void setTime(const float time);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Note: GO_PHASE is both: start phase and race phase
|
||||
|
35
src/network/event_rewinder.cpp
Normal file
35
src/network/event_rewinder.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2016 Joerg Henrichs
|
||||
//
|
||||
// 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 "network/event_rewinder.hpp"
|
||||
|
||||
#include "network/rewind_manager.hpp"
|
||||
|
||||
/** Constructor. It will add this object to the list of all rewindable
|
||||
* objects in the rewind manager.
|
||||
*/
|
||||
EventRewinder::EventRewinder()
|
||||
{
|
||||
} // Rewinder
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Destructor.
|
||||
*/
|
||||
EventRewinder::~EventRewinder()
|
||||
{
|
||||
} // ~EventRewinder
|
41
src/network/event_rewinder.hpp
Normal file
41
src/network/event_rewinder.hpp
Normal file
@ -0,0 +1,41 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2016 Joerg Henrichs
|
||||
//
|
||||
// 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.
|
||||
|
||||
#ifndef HEADER_EVENT_REWINDER_HPP
|
||||
#define HEADER_EVENT_REWINDER_HPP
|
||||
|
||||
class BareNetworkString;
|
||||
|
||||
class EventRewinder
|
||||
{
|
||||
public:
|
||||
EventRewinder();
|
||||
virtual ~EventRewinder();
|
||||
|
||||
/** Called when an event needs to be undone. This is called while going
|
||||
* backwards for rewinding - all stored events will get an 'undo' call.
|
||||
*/
|
||||
virtual void undo(BareNetworkString *buffer) = 0;
|
||||
|
||||
/** Called when an event needs to be replayed. This is called during
|
||||
* rewind, i.e. when going forward in time again.
|
||||
*/
|
||||
virtual void rewind(BareNetworkString *buffer) = 0;
|
||||
}; // EventRewinder
|
||||
#endif
|
||||
|
@ -137,6 +137,9 @@ public:
|
||||
memcpy(m_buffer.data(), data, len);
|
||||
} // BareNetworkString
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Allows to read a buffer from the beginning again. */
|
||||
void reset() { m_current_offset = 0; }
|
||||
// ------------------------------------------------------------------------
|
||||
BareNetworkString& encodeString(const std::string &value);
|
||||
BareNetworkString& encodeString(const irr::core::stringw &value);
|
||||
@ -225,6 +228,12 @@ public:
|
||||
} // operator+=
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Adds a floating point number */
|
||||
BareNetworkString& add(float f)
|
||||
{
|
||||
return addFloat(f);
|
||||
} // add
|
||||
// ------------------------------------------------------------------------
|
||||
/** Adds the xyz components of a Vec3 to the string. */
|
||||
BareNetworkString& add(const Vec3 &xyz)
|
||||
{
|
||||
|
@ -72,12 +72,12 @@ bool ControllerEventsProtocol::notifyEventAsynchronous(Event* event)
|
||||
Controller *controller = World::getWorld()->getKart(kart_id)
|
||||
->getController();
|
||||
KartControl *controls = controller->getControls();
|
||||
controls->m_brake = (serialized_1 & 0x40)!=0;
|
||||
controls->m_nitro = (serialized_1 & 0x20)!=0;
|
||||
controls->m_rescue = (serialized_1 & 0x10)!=0;
|
||||
controls->m_fire = (serialized_1 & 0x08)!=0;
|
||||
controls->m_look_back = (serialized_1 & 0x04)!=0;
|
||||
controls->m_skid = KartControl::SkidControl(serialized_1 & 0x03);
|
||||
controls->setBrake( (serialized_1 & 0x40)!=0);
|
||||
controls->setNitro( (serialized_1 & 0x20)!=0);
|
||||
controls->setRescue( (serialized_1 & 0x10)!=0);
|
||||
controls->setFire( (serialized_1 & 0x08)!=0);
|
||||
controls->setLookBack((serialized_1 & 0x04)!=0);
|
||||
controls->setSkidControl(KartControl::SkidControl(serialized_1 & 0x03));
|
||||
|
||||
controller->action(action, action_value);
|
||||
}
|
||||
@ -110,19 +110,19 @@ void ControllerEventsProtocol::controllerAction(Controller* controller,
|
||||
|
||||
KartControl* controls = controller->getControls();
|
||||
uint8_t serialized_1 = 0;
|
||||
serialized_1 |= (controls->m_brake==true);
|
||||
serialized_1 |= (controls->getBrake()==true);
|
||||
serialized_1 <<= 1;
|
||||
serialized_1 |= (controls->m_nitro==true);
|
||||
serialized_1 |= (controls->getNitro()==true);
|
||||
serialized_1 <<= 1;
|
||||
serialized_1 |= (controls->m_rescue==true);
|
||||
serialized_1 |= (controls->getRescue()==true);
|
||||
serialized_1 <<= 1;
|
||||
serialized_1 |= (controls->m_fire==true);
|
||||
serialized_1 |= (controls->getFire()==true);
|
||||
serialized_1 <<= 1;
|
||||
serialized_1 |= (controls->m_look_back==true);
|
||||
serialized_1 |= (controls->getLookBack()==true);
|
||||
serialized_1 <<= 2;
|
||||
serialized_1 += controls->m_skid;
|
||||
uint8_t serialized_2 = (uint8_t)(controls->m_accel*255.0);
|
||||
uint8_t serialized_3 = (uint8_t)(controls->m_steer*127.0);
|
||||
serialized_1 += controls->getSkidControl();
|
||||
uint8_t serialized_2 = (uint8_t)(controls->getAccel()*255.0);
|
||||
uint8_t serialized_3 = (uint8_t)(controls->getSteer()*127.0);
|
||||
|
||||
NetworkString *ns = getNetworkString(13);
|
||||
ns->addFloat(World::getWorld()->getTime());
|
||||
|
57
src/network/rewind_info.cpp
Normal file
57
src/network/rewind_info.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2016 Joerg Henrichs
|
||||
//
|
||||
// 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 "network/rewind_info.hpp"
|
||||
|
||||
#include "modes/world.hpp"
|
||||
#include "physics/physics.hpp"
|
||||
|
||||
/** Constructor for a state: it only takes the size, and allocates a buffer
|
||||
* for all state info.
|
||||
* \param size Necessary buffer size for a state.
|
||||
*/
|
||||
RewindInfo::RewindInfo(float time, bool is_confirmed)
|
||||
{
|
||||
m_time = time;
|
||||
m_is_confirmed = is_confirmed;
|
||||
} // RewindInfo
|
||||
|
||||
// ============================================================================
|
||||
RewindInfoTime::RewindInfoTime(float time)
|
||||
: RewindInfo(time, /*is_confirmed*/true)
|
||||
{
|
||||
} // RewindInfoTime
|
||||
|
||||
// ============================================================================
|
||||
RewindInfoState::RewindInfoState(float time, Rewinder *rewinder,
|
||||
BareNetworkString *buffer, bool is_confirmed)
|
||||
: RewindInfoRewinder(time, rewinder, buffer, is_confirmed)
|
||||
{
|
||||
m_local_physics_time = World::getWorld()->getPhysics()->getPhysicsWorld()
|
||||
->getLocalTime();
|
||||
} // RewindInfoState
|
||||
|
||||
// ============================================================================
|
||||
RewindInfoEvent::RewindInfoEvent(float time, EventRewinder *event_rewinder,
|
||||
BareNetworkString *buffer, bool is_confirmed)
|
||||
: RewindInfo(time, is_confirmed)
|
||||
{
|
||||
m_event_rewinder = event_rewinder;
|
||||
m_buffer = buffer;
|
||||
} // RewindInfoEvent
|
||||
|
222
src/network/rewind_info.hpp
Normal file
222
src/network/rewind_info.hpp
Normal file
@ -0,0 +1,222 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2016 Joerg Henrichs
|
||||
//
|
||||
// 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.
|
||||
|
||||
#ifndef HEADER_REWIND_INFO_HPP
|
||||
#define HEADER_REWIND_INFO_HPP
|
||||
|
||||
#include "network/event_rewinder.hpp"
|
||||
#include "network/network_string.hpp"
|
||||
#include "network/rewinder.hpp"
|
||||
#include "utils/leak_check.hpp"
|
||||
#include "utils/ptr_vector.hpp"
|
||||
|
||||
#include <assert.h>
|
||||
#include <vector>
|
||||
|
||||
/** Used to store rewind information for a given time for all rewind
|
||||
* instances.
|
||||
* Rewind information can either be a state (for example a kart would
|
||||
* have position, rotation, linear and angular velocity, ... as state),
|
||||
* or an event (for a kart that would be pressing or releasing of a key).
|
||||
* State changes and events can be delivered in different frequencies,
|
||||
* and might be released (to save memory) differently: A state can be
|
||||
* reproduced from a previous state by replaying the simulation taking
|
||||
* all events into account.
|
||||
*/
|
||||
|
||||
class RewindInfo
|
||||
{
|
||||
private:
|
||||
LEAK_CHECK();
|
||||
|
||||
/** Time when this state was taken. */
|
||||
float m_time;
|
||||
|
||||
/** A confirmed event is one that was sent from the server. When
|
||||
* rewinding we have to start with a confirmed state for each
|
||||
* object. */
|
||||
bool m_is_confirmed;
|
||||
|
||||
public:
|
||||
RewindInfo(float time, bool is_confirmed);
|
||||
|
||||
/** Called when going back in time to undo any rewind information. */
|
||||
virtual void undo() = 0;
|
||||
|
||||
/** This is called while going forwards in time again to reach current
|
||||
* time. */
|
||||
virtual void rewind() = 0;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
virtual ~RewindInfo() { }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the time at which this rewind state was saved. */
|
||||
float getTime() const { return m_time; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets if this RewindInfo is confirmed or not. */
|
||||
void setConfirmed(bool b) { m_is_confirmed = b; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns if this state is confirmed. */
|
||||
bool isConfirmed() const { return m_is_confirmed; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** If this rewind info is an event. Subclasses will overwrite this. */
|
||||
virtual bool isEvent() const { return false; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** If this rewind info is time info. Subclasses will overwrite this. */
|
||||
virtual bool isTime() const { return false; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** If this rewind info is an event. Subclasses will overwrite this. */
|
||||
virtual bool isState() const { return false; }
|
||||
// ------------------------------------------------------------------------
|
||||
}; // RewindInfo
|
||||
|
||||
// ============================================================================
|
||||
/** A rewind info abstract class that keeps track of a rewinder object, and
|
||||
* has a BareNetworkString buffer which is used to store a state or event.
|
||||
*/
|
||||
class RewindInfoRewinder : public RewindInfo
|
||||
{
|
||||
private:
|
||||
/** Pointer to the buffer which stores all states. */
|
||||
BareNetworkString *m_buffer;
|
||||
|
||||
protected:
|
||||
/** The Rewinder instance for which this data is. */
|
||||
Rewinder *m_rewinder;
|
||||
|
||||
public:
|
||||
RewindInfoRewinder(float time, Rewinder *rewinder,
|
||||
BareNetworkString *buffer, bool is_confirmed)
|
||||
: RewindInfo(time, is_confirmed)
|
||||
{
|
||||
m_rewinder = rewinder;
|
||||
m_buffer = buffer;
|
||||
} // RewindInfoRewinder
|
||||
// ------------------------------------------------------------------------
|
||||
virtual ~RewindInfoRewinder()
|
||||
{
|
||||
delete m_buffer;
|
||||
} // ~RewindInfoRewinder
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns a pointer to the state buffer. */
|
||||
BareNetworkString *getBuffer() const { return m_buffer; }
|
||||
}; // RewindInfoRewinder
|
||||
|
||||
// ============================================================================
|
||||
class RewindInfoTime : public RewindInfo
|
||||
{
|
||||
private:
|
||||
|
||||
public:
|
||||
RewindInfoTime(float time);
|
||||
virtual ~RewindInfoTime() {};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
virtual bool isTime() const { return true; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Called when going back in time to undo any rewind information.
|
||||
* Does actually nothing. */
|
||||
virtual void undo() {}
|
||||
// ------------------------------------------------------------------------
|
||||
/** Rewinds to this state. Nothing to be done for time info. */
|
||||
virtual void rewind() {}
|
||||
}; // class RewindInfoTime
|
||||
|
||||
// ============================================================================
|
||||
class RewindInfoState: public RewindInfoRewinder
|
||||
{
|
||||
private:
|
||||
/** The 'left over' time from the physics. */
|
||||
float m_local_physics_time;
|
||||
|
||||
public:
|
||||
RewindInfoState(float time, Rewinder *rewinder,
|
||||
BareNetworkString *buffer, bool is_confirmed);
|
||||
virtual ~RewindInfoState() {};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the left-over physics time. */
|
||||
float getLocalPhysicsTime() const { return m_local_physics_time; }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual bool isState() const { return true; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Called when going back in time to undo any rewind information.
|
||||
* It calls undoState in the rewinder. */
|
||||
virtual void undo()
|
||||
{
|
||||
m_rewinder->undoState(getBuffer());
|
||||
} // undo
|
||||
// ------------------------------------------------------------------------
|
||||
/** Rewinds to this state. This is called while going forwards in time
|
||||
* again to reach current time. It will call rewindToState().
|
||||
* if the state is a confirmed state. */
|
||||
virtual void rewind()
|
||||
{
|
||||
if (isConfirmed())
|
||||
m_rewinder->rewindToState(getBuffer());
|
||||
else
|
||||
{
|
||||
// TODO
|
||||
// Handle replacing of stored states.
|
||||
}
|
||||
} // rewind
|
||||
}; // class RewindInfoState
|
||||
|
||||
// ============================================================================
|
||||
class RewindInfoEvent : public RewindInfo
|
||||
{
|
||||
private:
|
||||
/** Pointer to the event rewinder responsible for this event. */
|
||||
EventRewinder *m_event_rewinder;
|
||||
|
||||
/** Buffer with the event data. */
|
||||
BareNetworkString *m_buffer;
|
||||
public:
|
||||
RewindInfoEvent(float time, EventRewinder *event_rewinder,
|
||||
BareNetworkString *buffer, bool is_confirmed);
|
||||
virtual ~RewindInfoEvent()
|
||||
{
|
||||
delete m_buffer;
|
||||
} // ~RewindInfoEvent
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
virtual bool isEvent() const { return true; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Called when going back in time to undo any rewind information.
|
||||
* It calls undoEvent in the rewinder. */
|
||||
virtual void undo()
|
||||
{
|
||||
m_buffer->reset();
|
||||
m_event_rewinder->undo(m_buffer);
|
||||
} // undo
|
||||
// ------------------------------------------------------------------------
|
||||
/** This is called while going forwards in time again to reach current
|
||||
* time. Calls rewindEvent().
|
||||
*/
|
||||
virtual void rewind()
|
||||
{
|
||||
// Make sure to reset the buffer so we read from the beginning
|
||||
m_buffer->reset();
|
||||
m_event_rewinder->rewind(m_buffer);
|
||||
} // rewind
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the buffer with the event information in it. */
|
||||
BareNetworkString *getBuffer() { return m_buffer; }
|
||||
}; // class RewindIndoEvent
|
||||
|
||||
#endif
|
405
src/network/rewind_manager.cpp
Normal file
405
src/network/rewind_manager.cpp
Normal file
@ -0,0 +1,405 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2013 Joerg Henrichs
|
||||
//
|
||||
// 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 "network/rewind_manager.hpp"
|
||||
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "network/network_string.hpp"
|
||||
#include "network/rewinder.hpp"
|
||||
#include "network/rewind_info.hpp"
|
||||
#include "physics/physics.hpp"
|
||||
#include "race/history.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
RewindManager* RewindManager::m_rewind_manager = NULL;
|
||||
bool RewindManager::m_enable_rewind_manager = false;
|
||||
|
||||
/** Creates the singleton. */
|
||||
RewindManager *RewindManager::create()
|
||||
{
|
||||
assert(!m_rewind_manager);
|
||||
m_rewind_manager = new RewindManager();
|
||||
return m_rewind_manager;
|
||||
} // create
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Destroys the singleton. */
|
||||
void RewindManager::destroy()
|
||||
{
|
||||
assert(m_rewind_manager);
|
||||
delete m_rewind_manager;
|
||||
m_rewind_manager = NULL;
|
||||
} // destroy
|
||||
|
||||
// ============================================================================
|
||||
/** The constructor.
|
||||
*/
|
||||
RewindManager::RewindManager()
|
||||
{
|
||||
reset();
|
||||
} // RewindManager
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Frees all saved state information. Note that the Rewinder data must be
|
||||
* freed elsewhere.
|
||||
*/
|
||||
RewindManager::~RewindManager()
|
||||
{
|
||||
// Destroying the
|
||||
for(unsigned int i=0; i<m_rewind_info.size(); i++)
|
||||
{
|
||||
delete m_rewind_info[i];
|
||||
m_rewind_info[i] = NULL;
|
||||
}
|
||||
m_rewind_info.clear();
|
||||
} // ~RewindManager
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Frees all saved state information and all destroyable rewinder.
|
||||
*/
|
||||
void RewindManager::reset()
|
||||
{
|
||||
#ifdef REWIND_SEARCH_STATS
|
||||
m_count_of_comparisons = 0;
|
||||
m_count_of_searches = 0;
|
||||
#endif
|
||||
m_is_rewinding = false;
|
||||
m_overall_state_size = 0;
|
||||
m_state_frequency = 0.1f; // save 10 states a second
|
||||
m_last_saved_state = -9999.9f; // forces initial state save
|
||||
|
||||
if(!m_enable_rewind_manager) return;
|
||||
|
||||
AllRewinder::iterator r = m_all_rewinder.begin();
|
||||
while(r!=m_all_rewinder.end())
|
||||
{
|
||||
if(!(*r)->canBeDestroyed())
|
||||
{
|
||||
r++;
|
||||
continue;
|
||||
}
|
||||
Rewinder *rewinder = *r;
|
||||
r = m_all_rewinder.erase(r);
|
||||
// FIXME Do we really want to delete this here?
|
||||
delete rewinder;
|
||||
}
|
||||
|
||||
for(unsigned int i=0; i<m_rewind_info.size(); i++)
|
||||
{
|
||||
delete m_rewind_info[i];
|
||||
}
|
||||
m_rewind_info.clear();
|
||||
} // reset
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void RewindManager::insertRewindInfo(RewindInfo *ri)
|
||||
{
|
||||
#ifdef REWIND_SEARCH_STATS
|
||||
m_count_of_searches++;
|
||||
#endif
|
||||
float t = ri->getTime();
|
||||
|
||||
if(ri->isEvent())
|
||||
{
|
||||
// If there are several infos for the same time t,
|
||||
// events must be inserted at the end
|
||||
AllRewindInfo::reverse_iterator i = m_rewind_info.rbegin();
|
||||
while(i!=m_rewind_info.rend() &&
|
||||
(*i)->getTime() > t)
|
||||
{
|
||||
#ifdef REWIND_SEARCH_STATS
|
||||
m_count_of_comparisons++;
|
||||
#endif
|
||||
i++;
|
||||
}
|
||||
AllRewindInfo::iterator insert_point = i.base();
|
||||
m_rewind_info.insert(insert_point,ri);
|
||||
return;
|
||||
|
||||
}
|
||||
else // is a state
|
||||
{
|
||||
// If there are several infos for the same time t,
|
||||
// a state must be inserted first
|
||||
AllRewindInfo::reverse_iterator i = m_rewind_info.rbegin();
|
||||
while(i!=m_rewind_info.rend() && (*i)->getTime() >= t)
|
||||
{
|
||||
#ifdef REWIND_SEARCH_STATS
|
||||
m_count_of_comparisons++;
|
||||
#endif
|
||||
i++;
|
||||
}
|
||||
AllRewindInfo::iterator insert_point = i.base();
|
||||
m_rewind_info.insert(insert_point,ri);
|
||||
return;
|
||||
}
|
||||
} // insertRewindInfo
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Returns the first (i.e. lowest) index i in m_rewind_info which fulfills
|
||||
* time(i) < target_time <= time(i+1) and is a state. This is the state
|
||||
* from which a rewind can start - all states for the karts will be well
|
||||
* defined.
|
||||
* \param time Time for which an index is searched.
|
||||
* \return Index in m_rewind_info after which to add rewind data.
|
||||
*/
|
||||
unsigned int RewindManager::findFirstIndex(float target_time) const
|
||||
{
|
||||
// For now do a linear search, even though m_rewind_info is sorted
|
||||
// I would expect that most insertions will be towards the (very)
|
||||
// end of the list, since rewinds should be for short periods of time.
|
||||
// Note that after finding an entry in a binary search, you still
|
||||
// have to do a linear search to find the last entry with the same
|
||||
// time in order to minimise the later necessary memory move.
|
||||
|
||||
// Gather some statistics about search for now:
|
||||
#ifdef REWIND_SEARCH_STATS
|
||||
m_count_of_searches++;
|
||||
#endif
|
||||
int index = m_rewind_info.size()-1;
|
||||
int index_last_state = -1;
|
||||
while(index>=0)
|
||||
{
|
||||
#ifdef REWIND_SEARCH_STATS
|
||||
m_count_of_comparisons++;
|
||||
#endif
|
||||
if(m_rewind_info[index]->isState())
|
||||
{
|
||||
if(m_rewind_info[index]->getTime()<target_time)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
index_last_state = index;
|
||||
}
|
||||
index--;
|
||||
}
|
||||
|
||||
if(index_last_state<0)
|
||||
{
|
||||
Log::fatal("RewindManager",
|
||||
"Can't find any state when rewinding to %f - aborting.",
|
||||
target_time);
|
||||
}
|
||||
|
||||
// Otherwise use the last found state - not much we can do in this case.
|
||||
Log::error("RewindManager",
|
||||
"Can't find state to rewind to for time %f, using %f.",
|
||||
target_time, m_rewind_info[index_last_state]->getTime());
|
||||
return index_last_state; // avoid compiler warning
|
||||
} // findFirstIndex
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Adds an event to the rewind data. The data to be stored must be allocated
|
||||
* and not freed by the caller!
|
||||
* \param time Time at which the event was recorded.
|
||||
* \param buffer Pointer to the event data.
|
||||
*/
|
||||
void RewindManager::addEvent(EventRewinder *event_rewinder,
|
||||
BareNetworkString *buffer)
|
||||
{
|
||||
if(m_is_rewinding)
|
||||
{
|
||||
delete buffer;
|
||||
Log::error("RewindManager", "Adding event when rewinding");
|
||||
return;
|
||||
}
|
||||
RewindInfo *ri = new RewindInfoEvent(getCurrentTime(), event_rewinder,
|
||||
buffer, /*is confirmed*/true);
|
||||
insertRewindInfo(ri);
|
||||
} // addEvent
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Determines if a new state snapshot should be taken, and if so calls all
|
||||
* rewinder to do so.
|
||||
* \param dt Time step size.
|
||||
*/
|
||||
void RewindManager::saveStates()
|
||||
{
|
||||
if(!m_enable_rewind_manager ||
|
||||
m_all_rewinder.size()==0 ||
|
||||
m_is_rewinding ) return;
|
||||
|
||||
float time = World::getWorld()->getTime();
|
||||
if(time - m_last_saved_state < m_state_frequency)
|
||||
{
|
||||
// No full state necessary, add a dummy entry for the time
|
||||
// which increases replay precision (same time step size)
|
||||
RewindInfo *ri = new RewindInfoTime(getCurrentTime());
|
||||
insertRewindInfo(ri);
|
||||
return;
|
||||
}
|
||||
|
||||
// For now always create a snapshot.
|
||||
for(unsigned int i=0; i<m_all_rewinder.size(); i++)
|
||||
{
|
||||
BareNetworkString *buffer = m_all_rewinder[i]->saveState();
|
||||
if(buffer && buffer->size()>=0)
|
||||
{
|
||||
m_overall_state_size += buffer->size();
|
||||
RewindInfo *ri = new RewindInfoState(getCurrentTime(),
|
||||
m_all_rewinder[i], buffer,
|
||||
/*is_confirmed*/true);
|
||||
assert(ri);
|
||||
insertRewindInfo(ri);
|
||||
} // size >= 0
|
||||
else
|
||||
delete buffer; // NULL or 0 byte buffer
|
||||
}
|
||||
|
||||
Log::verbose("RewindManager", "%f allocated %ld bytes search %d/%d=%f",
|
||||
World::getWorld()->getTime(), m_overall_state_size,
|
||||
m_count_of_comparisons, m_count_of_searches,
|
||||
float(m_count_of_comparisons)/ float(m_count_of_searches) );
|
||||
|
||||
m_last_saved_state = time;
|
||||
} // saveStates
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Rewinds to the specified time.
|
||||
* \param t Time to rewind to.
|
||||
*/
|
||||
void RewindManager::rewindTo(float rewind_time)
|
||||
{
|
||||
assert(!m_is_rewinding);
|
||||
m_is_rewinding = true;
|
||||
Log::info("rewind", "Rewinding to %f", rewind_time);
|
||||
history->doReplayHistory(History::HISTORY_NONE);
|
||||
|
||||
// First find the state to which we need to rewind
|
||||
// ------------------------------------------------
|
||||
unsigned int index = findFirstIndex(rewind_time);
|
||||
|
||||
if(!m_rewind_info[index]->isState())
|
||||
{
|
||||
Log::error("RewindManager", "No state for rewind to %f, state %d.",
|
||||
rewind_time, index);
|
||||
return;
|
||||
}
|
||||
|
||||
// Then undo the rewind infos going backwards in time
|
||||
// --------------------------------------------------
|
||||
for(int i=m_rewind_info.size()-1; i>=(int)index; i--)
|
||||
{
|
||||
m_rewind_info[i]->undo();
|
||||
|
||||
// Now all states after the time we rewind to are not confirmed
|
||||
// anymore. They need to be rewritten when going forward during
|
||||
// the rewind.
|
||||
if(m_rewind_info[i]->isState() &&
|
||||
m_rewind_info[i]->getTime() > m_rewind_info[index]->getTime() )
|
||||
m_rewind_info[i]->setConfirmed(false);
|
||||
} // for i>state
|
||||
|
||||
|
||||
// Rewind the required state(s)
|
||||
// ----------------------------
|
||||
World *world = World::getWorld();
|
||||
float current_time = world->getTime();
|
||||
|
||||
// Get the (first) full state to which we have to rewind
|
||||
RewindInfoState *state =
|
||||
dynamic_cast<RewindInfoState*>(m_rewind_info[index]);
|
||||
|
||||
// Store the time to which we have to replay to
|
||||
float exact_rewind_time = state->getTime();
|
||||
|
||||
// Now start the rewind with the full state:
|
||||
world->setTime(exact_rewind_time);
|
||||
float local_physics_time = state->getLocalPhysicsTime();
|
||||
world->getPhysics()->getPhysicsWorld()->setLocalTime(local_physics_time);
|
||||
|
||||
// Restore all states from the current time - the full state of a race
|
||||
// will be potentially stored in several state objects. State can be NULL
|
||||
// if the next event is not a state
|
||||
while(state && state->getTime()==exact_rewind_time)
|
||||
{
|
||||
state->rewind();
|
||||
index++;
|
||||
if(index>=m_rewind_info.size()) break;
|
||||
state = dynamic_cast<RewindInfoState*>(m_rewind_info[index]);
|
||||
}
|
||||
|
||||
// Now go forward through the list of rewind infos:
|
||||
// ------------------------------------------------
|
||||
while( world->getTime() < current_time &&
|
||||
index < (int)m_rewind_info.size() )
|
||||
{
|
||||
// Now handle all states and events at the current time before
|
||||
// updating the world:
|
||||
while(index < (int)m_rewind_info.size() &&
|
||||
m_rewind_info[index]->getTime()<=world->getTime()+0.001f)
|
||||
{
|
||||
if(m_rewind_info[index]->isState())
|
||||
{
|
||||
// TOOD: replace the old state with a new state.
|
||||
// For now just set it to confirmed
|
||||
m_rewind_info[index]->setConfirmed(true);
|
||||
}
|
||||
else if(m_rewind_info[index]->isEvent())
|
||||
{
|
||||
m_rewind_info[index]->rewind();
|
||||
}
|
||||
index++;
|
||||
}
|
||||
float dt = determineTimeStepSize(index, current_time);
|
||||
world->updateWorld(dt);
|
||||
#define SHOW_ROLLBACK
|
||||
#ifdef SHOW_ROLLBACK
|
||||
irr_driver->update(dt);
|
||||
#endif
|
||||
world->updateTime(dt);
|
||||
|
||||
}
|
||||
m_is_rewinding = false;
|
||||
|
||||
} // rewindTo
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Determines the next time step size to use when recomputing the physics.
|
||||
* The time step size is either 1/60 (default physics), or less, if there
|
||||
* is an even to handle before that time.
|
||||
* \param next_state The next state to replay.
|
||||
* \param end_time The end time to which we must replay forward. Don't
|
||||
* return a dt that would be bigger tham this value.
|
||||
* \return The time step size to use in the next simulation step.
|
||||
*/
|
||||
float RewindManager::determineTimeStepSize(int next_state, float end_time)
|
||||
{
|
||||
// If there is a next state (which is known to have a different time)
|
||||
// use the time difference to determine the time step size.
|
||||
if(next_state < (int)m_rewind_info.size())
|
||||
return m_rewind_info[next_state]->getTime() - World::getWorld()->getTime();
|
||||
|
||||
// Otherwise, i.e. we are rewinding the last state/event, take the
|
||||
// difference between that time and the world time at which the rewind
|
||||
// was triggered.
|
||||
return end_time - m_rewind_info[next_state-1]->getTime();
|
||||
|
||||
|
||||
|
||||
float dt = 1.0f/60.0f;
|
||||
float t = World::getWorld()->getTime();
|
||||
if(m_rewind_info[next_state]->getTime() < t + dt)
|
||||
{
|
||||
// Since we have RewindInfo at that time, it is certain that
|
||||
/// this time is before (or at) end_time, not after.
|
||||
return m_rewind_info[next_state]->getTime()-t;
|
||||
}
|
||||
return t+dt < end_time ? dt : end_time - t;
|
||||
} // determineTimeStepSize
|
194
src/network/rewind_manager.hpp
Normal file
194
src/network/rewind_manager.hpp
Normal file
@ -0,0 +1,194 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2013 Joerg Henrichs
|
||||
//
|
||||
// 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.
|
||||
|
||||
#ifndef HEADER_REWIND_MANAGER_HPP
|
||||
#define HEADER_REWIND_MANAGER_HPP
|
||||
|
||||
#include "network/rewinder.hpp"
|
||||
#include "utils/ptr_vector.hpp"
|
||||
|
||||
#include <assert.h>
|
||||
#include <vector>
|
||||
|
||||
class RewindInfo;
|
||||
class EventRewinder;
|
||||
|
||||
/** \ingroup network
|
||||
* This class manages rewinding. It keeps track of:
|
||||
* - states for each rewindable object (for example a kart would have
|
||||
* its position, rotation, linear and angular velocity etc as state)
|
||||
* States can be confirmed (i.e. were received by the network server
|
||||
* and are therefore confirmed to be conrrect), or not (just a snapshot
|
||||
* on this client, which can save time in rewinding later).
|
||||
* - events for each rewindable object (for example any change in the kart
|
||||
* controls, like steering, fire, ... are an event). While states can be
|
||||
* discarded (especially unconfirmed ones), e.g. to save space, events
|
||||
* will always be kept (in order to allow replaying).
|
||||
* For each object that is to be rewinded an instance of Rewinder needs to be
|
||||
* declared (usually inside of the object it can rewind). This instance
|
||||
* is automatically registered with the RewindManager.
|
||||
* All states and events are stored in a RewindInfo object. All RewindInfo
|
||||
* objects are stored in a list sorted by time.
|
||||
* When a rewind to time T is requested, the following takes place:
|
||||
* 1. Go back in time:
|
||||
* Determine the latest time t_min < T so that each rewindable objects
|
||||
* has at least one state before T. For each state that is skipped during
|
||||
* this process `undoState()` is being called, and for each event
|
||||
* `undoEvent()` of the Rewinder.
|
||||
* 2. Restore state at time `t_min`
|
||||
* For each Rewinder the state at time t_min is restored by calling
|
||||
* `rewindToState(char *)`.
|
||||
* TODO: atm there is no guarantee that each object will have a state
|
||||
* at a given time. We either need to work around that, or make sure
|
||||
* to store at least an unconfirmed state whenever we receive a
|
||||
* confirmed state.
|
||||
* 3. Rerun the simulation till the current time t_current is reached:
|
||||
* 1. Determine the time `t_next` of the next frame. This is either
|
||||
* current_time + 1/60 (physics default time step size), or less
|
||||
* if RewindInfo at an earlier time is available).
|
||||
* This determines the time step size for the next frame (i.e.
|
||||
* `t_next - t_current`).
|
||||
* 2. For all RewindInfo at time t_next call:
|
||||
* - `restoreState()` if the RewindInfo is a confirmed state
|
||||
* - `discardState()` if the RewindInfo is an unconfirmed state
|
||||
* TODO: still missing, and instead of discard perhaps
|
||||
* store a new state??
|
||||
* - `rewindToEvent()` if the RewindInfo is an event
|
||||
* 3. Do one step of world simulation, using the updated (confirmed)
|
||||
* states and newly set events (e.g. kart input).
|
||||
*/
|
||||
|
||||
class RewindManager
|
||||
{
|
||||
private:
|
||||
/** Singleton pointer. */
|
||||
static RewindManager *m_rewind_manager;
|
||||
|
||||
/** En- or Disable the rewind manager. This is used to disable storing
|
||||
* rewind data in case of local races only. */
|
||||
static bool m_enable_rewind_manager;
|
||||
|
||||
typedef std::vector<Rewinder *> AllRewinder;
|
||||
|
||||
/** A list of all objects that can be rewound. */
|
||||
AllRewinder m_all_rewinder;
|
||||
|
||||
/** Pointer to all saved states. */
|
||||
typedef std::vector<RewindInfo*> AllRewindInfo;
|
||||
|
||||
AllRewindInfo m_rewind_info;
|
||||
|
||||
/** Overall amount of memory allocated by states. */
|
||||
unsigned int m_overall_state_size;
|
||||
|
||||
/** Indicates if currently a rewind is happening. */
|
||||
bool m_is_rewinding;
|
||||
|
||||
/** How much time between consecutive state saves. */
|
||||
float m_state_frequency;
|
||||
|
||||
/** Time at which the last state was saved. */
|
||||
float m_last_saved_state;
|
||||
|
||||
/** The current time to be used in all states/events. This is used to
|
||||
* give all states and events during one frame the same time, even
|
||||
* if e.g. states are saved before world time is increased, other
|
||||
* events later. */
|
||||
float m_current_time;
|
||||
|
||||
/** The current time step size. */
|
||||
float m_time_step;
|
||||
|
||||
#define REWIND_SEARCH_STATS
|
||||
|
||||
#ifdef REWIND_SEARCH_STATS
|
||||
/** Gather some statistics about how many comparisons we do,
|
||||
* to find out if it's worth doing a binary search.*/
|
||||
mutable int m_count_of_comparisons;
|
||||
mutable int m_count_of_searches;
|
||||
#endif
|
||||
|
||||
RewindManager();
|
||||
~RewindManager();
|
||||
unsigned int findFirstIndex(float time) const;
|
||||
void insertRewindInfo(RewindInfo *ri);
|
||||
float determineTimeStepSize(int state, float max_time);
|
||||
public:
|
||||
// First static functions to manage rewinding.
|
||||
// ===========================================
|
||||
static RewindManager *create();
|
||||
static void destroy();
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets the time that is to be used for all further states or events,
|
||||
* and the time step size. This is necessary so that states/events before
|
||||
* and after World::m_time is increased have the same time stamp.
|
||||
* \param t Time.
|
||||
* \param dt Time step size.
|
||||
*/
|
||||
void setCurrentTime(float t, float dt)
|
||||
{
|
||||
m_current_time = t;
|
||||
m_time_step = dt;
|
||||
} // setCurrentTime
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the current time. */
|
||||
float getCurrentTime() const { return m_current_time; }
|
||||
// ------------------------------------------------------------------------
|
||||
float getCurrentTimeStep() const { return m_time_step; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** En- or disables rewinding. */
|
||||
static void setEnable(bool m) { m_enable_rewind_manager = m;}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns if rewinding is enabled or not. */
|
||||
static bool isEnabled() { return m_enable_rewind_manager; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the singleton. This function will not automatically create
|
||||
* the singleton. */
|
||||
static RewindManager *get()
|
||||
{
|
||||
assert(m_rewind_manager);
|
||||
return m_rewind_manager;
|
||||
} // get
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
void reset();
|
||||
void saveStates();
|
||||
void rewindTo(float target_time);
|
||||
void addEvent(EventRewinder *event_rewinder, BareNetworkString *buffer);
|
||||
// ------------------------------------------------------------------------
|
||||
/** Adds a Rewinder to the list of all rewinders.
|
||||
* \return true If rewinding is enabled, false otherwise.
|
||||
*/
|
||||
bool addRewinder(Rewinder *rewinder)
|
||||
{
|
||||
if(!m_enable_rewind_manager) return false;
|
||||
m_all_rewinder.push_back(rewinder);
|
||||
return true;
|
||||
} // addRewinder
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns true if currently a rewind is happening. */
|
||||
bool isRewinding() const { return m_is_rewinding; }
|
||||
}; // RewindManager
|
||||
|
||||
|
||||
#endif
|
||||
|
37
src/network/rewinder.cpp
Normal file
37
src/network/rewinder.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2013 Joerg Henrichs
|
||||
//
|
||||
// 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 "network/rewinder.hpp"
|
||||
|
||||
#include "network/rewind_manager.hpp"
|
||||
|
||||
/** Constructor. It will add this object to the list of all rewindable
|
||||
* objects in the rewind manager.
|
||||
*/
|
||||
Rewinder::Rewinder(bool can_be_destroyed)
|
||||
{
|
||||
m_can_be_destroyed = can_be_destroyed;
|
||||
RewindManager::get()->addRewinder(this);
|
||||
} // Rewinder
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Destructor.
|
||||
*/
|
||||
Rewinder::~Rewinder()
|
||||
{
|
||||
} // ~Rewinder
|
71
src/network/rewinder.hpp
Normal file
71
src/network/rewinder.hpp
Normal file
@ -0,0 +1,71 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2013 Joerg Henrichs
|
||||
//
|
||||
// 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.
|
||||
|
||||
#ifndef HEADER_REWINDER_HPP
|
||||
#define HEADER_REWINDER_HPP
|
||||
|
||||
class BareNetworkString;
|
||||
|
||||
class Rewinder
|
||||
{
|
||||
private:
|
||||
bool m_can_be_destroyed;
|
||||
public:
|
||||
Rewinder(bool can_be_destroyed);
|
||||
virtual ~Rewinder();
|
||||
|
||||
/** Provides a copy of the state of the object in one memory buffer.
|
||||
* The memory is managed by the RewindManager.
|
||||
* \param[out] buffer The address of the memory buffer with the state.
|
||||
* \return Size of the buffer, or -1 in case of an error.
|
||||
*/
|
||||
virtual BareNetworkString* saveState() const = 0;
|
||||
|
||||
/** Called when an event needs to be undone. This is called while going
|
||||
* backwards for rewinding - all stored events will get an 'undo' call.
|
||||
*/
|
||||
virtual void undoEvent(BareNetworkString *buffer) = 0;
|
||||
|
||||
/** Called when an event needs to be replayed. This is called during
|
||||
* rewind, i.e. when going forward in time again.
|
||||
*/
|
||||
virtual void rewindToEvent(BareNetworkString *buffer) = 0;
|
||||
|
||||
/** Called when a state needs to be replayed. This is called during
|
||||
* rewind, i.e. when going forward in time again, and only for confirmed
|
||||
* states.
|
||||
*/
|
||||
virtual void rewindToState(BareNetworkString *buffer) = 0;
|
||||
|
||||
/** Undo the effects of the given state, but do not rewind to that
|
||||
* state (which is done by rewindTo). This is called while going
|
||||
* backwards for rewinding - all stored events will get an 'undo' call.
|
||||
*/
|
||||
virtual void undoState(BareNetworkString *buffer) = 0;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
/** Nothing to do here. */
|
||||
virtual void reset() {};
|
||||
// -------------------------------------------------------------------------
|
||||
/** True if this rewinder can be destroyed. Karts can not be destroyed,
|
||||
* cakes can. This is used by the RewindManager in reset. */
|
||||
bool canBeDestroyed() const { return m_can_be_destroyed; }
|
||||
|
||||
}; // Rewinder
|
||||
#endif
|
||||
|
@ -91,10 +91,9 @@ namespace Online
|
||||
/** Request a login using the saved credentials of the user. */
|
||||
void OnlinePlayerProfile::requestSavedSession()
|
||||
{
|
||||
SignInRequest *request = NULL;
|
||||
if (m_online_state == OS_SIGNED_OUT && hasSavedSession())
|
||||
{
|
||||
request = new SignInRequest(true);
|
||||
SignInRequest *request = new SignInRequest(true);
|
||||
setUserDetails(request, "saved-session");
|
||||
|
||||
// The userid must be taken from the saved data,
|
||||
|
@ -117,8 +117,7 @@ void btKart::reset()
|
||||
updateWheelTransform(i, true);
|
||||
}
|
||||
m_visual_wheels_touch_ground = false;
|
||||
m_zipper_active = false;
|
||||
m_zipper_velocity = btScalar(0);
|
||||
m_zipper_speed = btScalar(0);
|
||||
m_skid_angular_velocity = 0;
|
||||
m_is_skidding = false;
|
||||
m_allow_sliding = false;
|
||||
@ -813,7 +812,7 @@ void btKart::updateFriction(btScalar timeStep)
|
||||
(btRigidBody*) wheelInfo.m_raycastInfo.m_groundObject;
|
||||
if(!groundObject) continue;
|
||||
|
||||
if(m_zipper_active && m_zipper_velocity > 0)
|
||||
if(m_zipper_speed > 0)
|
||||
{
|
||||
if (wheel==2 || wheel==3)
|
||||
{
|
||||
@ -821,7 +820,7 @@ void btKart::updateFriction(btScalar timeStep)
|
||||
// reached. So compute the impulse to accelerate the
|
||||
// kart up to that speed:
|
||||
m_forwardImpulse[wheel] =
|
||||
0.5f*(m_zipper_velocity -
|
||||
0.5f*(m_zipper_speed -
|
||||
getRigidBody()->getLinearVelocity().length())
|
||||
/ m_chassisBody->getInvMass();
|
||||
}
|
||||
@ -850,7 +849,7 @@ void btKart::updateFriction(btScalar timeStep)
|
||||
// bullet then tries to offset by applying a backward
|
||||
// impulse - which is a bit too big, causing a impulse
|
||||
// backwards, ... till the kart is shaking backwards and
|
||||
// forwards. By onlyu applying half of the impulse in cae
|
||||
// forwards. By only applying half of the impulse in case
|
||||
// of low friction this goes away.
|
||||
if(wheelInfo.m_brake && fabsf(rollingFriction)<10)
|
||||
rollingFriction*=0.5f;
|
||||
@ -885,8 +884,8 @@ void btKart::updateFriction(btScalar timeStep)
|
||||
} // for (int wheel=0; wheel<getNumWheels(); wheel++)
|
||||
|
||||
|
||||
m_zipper_active = false;
|
||||
m_zipper_velocity = 0;
|
||||
// Note: don't reset zipper speed, or the kart rewinder will
|
||||
// get incorrect zipper information.
|
||||
|
||||
// The kart just stopped skidding. Adjust the velocity so that
|
||||
// it points in the right direction.
|
||||
@ -1064,8 +1063,12 @@ void btKart::setSliding(bool active)
|
||||
*/
|
||||
void btKart::instantSpeedIncreaseTo(float speed)
|
||||
{
|
||||
m_zipper_active = true;
|
||||
m_zipper_velocity = speed;
|
||||
// Avoid that a speed 'increase' might cause a slowdown
|
||||
if (m_chassisBody->getLinearVelocity().length2() > speed*speed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_zipper_speed = speed;
|
||||
} // activateZipper
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -69,12 +69,9 @@ private:
|
||||
btScalar m_damping;
|
||||
btVehicleRaycaster *m_vehicleRaycaster;
|
||||
|
||||
/** True if a zipper is active for that kart. */
|
||||
bool m_zipper_active;
|
||||
|
||||
/** The zipper velocity (i.e. the velocity the kart should reach in
|
||||
/** The zipper speed (i.e. the velocity the kart should reach in
|
||||
* the first frame that the zipper is active). */
|
||||
btScalar m_zipper_velocity;
|
||||
btScalar m_zipper_speed;
|
||||
|
||||
/** The angular velocity to be applied when the kart skids.
|
||||
* 0 means no skidding. */
|
||||
@ -274,6 +271,11 @@ public:
|
||||
m_additional_rotation = rot/t;
|
||||
m_time_additional_rotation = t;
|
||||
} // setTimedTorque
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the current zipper speed. */
|
||||
float getInstantSpeedIncrease() const { return m_zipper_speed; }
|
||||
// ------------------------------------------------------------------------
|
||||
void resetInstantSpeed() { m_zipper_speed = 0; }
|
||||
}; // class btKart
|
||||
|
||||
#endif //BT_KART_HPP
|
||||
|
@ -38,8 +38,13 @@ public:
|
||||
|
||||
/** Resets m_localTime to 0. This allows more precise replay of
|
||||
* physics, which is important for replaying histories. */
|
||||
virtual void resetLocalTime() { m_localTime = 0; }
|
||||
|
||||
void resetLocalTime() { m_localTime = 0; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets the local time to a specified value. Used in rewinding. */
|
||||
void setLocalTime(float t) { m_localTime = t; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Gets the local time. */
|
||||
float getLocalTime() const { return m_localTime; }
|
||||
}; // STKDynamicsWorld
|
||||
#endif
|
||||
/* EOF */
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "io/file_manager.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "karts/abstract_kart.hpp"
|
||||
#include "network/rewind_manager.hpp"
|
||||
#include "physics/physics.hpp"
|
||||
#include "race/race_manager.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
@ -74,19 +75,6 @@ void History::allocateMemory(int number_of_frames)
|
||||
m_all_rotations.resize(number_of_frames*num_karts);
|
||||
} // allocateMemory
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Depending on mode either saves the data for the current time step, or
|
||||
* replays the data.
|
||||
* /param dt Time step.
|
||||
*/
|
||||
void History::update(float dt)
|
||||
{
|
||||
if(m_replay_mode==HISTORY_NONE)
|
||||
updateSaving(dt);
|
||||
else
|
||||
updateReplay(dt);
|
||||
} // update
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Saves the current history.
|
||||
* \param dt Time step size.
|
||||
@ -123,7 +111,7 @@ void History::updateSaving(float dt)
|
||||
/** Sets the kart position and controls to the recorded history value.
|
||||
* \param dt Time step size.
|
||||
*/
|
||||
void History::updateReplay(float dt)
|
||||
float History::updateReplayAndGetDT()
|
||||
{
|
||||
m_current++;
|
||||
World *world = World::getWorld();
|
||||
@ -131,9 +119,17 @@ void History::updateReplay(float dt)
|
||||
{
|
||||
Log::info("History", "Replay finished");
|
||||
m_current = 0;
|
||||
// This is useful to use a reproducable rewind problem:
|
||||
// replay it with history, for debugging only
|
||||
#undef DO_REWIND_AT_END_OF_HISTORY
|
||||
#ifdef DO_REWIND_AT_END_OF_HISTORY
|
||||
RewindManager::get()->rewindTo(5.0f);
|
||||
exit(-1);
|
||||
#else
|
||||
// Note that for physics replay all physics parameters
|
||||
// need to be reset, e.g. velocity, ...
|
||||
world->reset();
|
||||
#endif
|
||||
}
|
||||
unsigned int num_karts = world->getNumKarts();
|
||||
for(unsigned k=0; k<num_karts; k++)
|
||||
@ -147,10 +143,11 @@ void History::updateReplay(float dt)
|
||||
}
|
||||
else
|
||||
{
|
||||
kart->setControls(m_all_controls[index]);
|
||||
kart->getControls().set(m_all_controls[index]);
|
||||
}
|
||||
}
|
||||
} // updateReplay
|
||||
return m_all_deltas[m_current];
|
||||
} // updateReplayAndGetDT
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Saves the history stored in the internal data structures into a file called
|
||||
@ -208,8 +205,8 @@ void History::Save()
|
||||
for(int k=0; k<num_karts; k++)
|
||||
{
|
||||
fprintf(fd, "%f %f %d %f %f %f %f %f %f %f\n",
|
||||
m_all_controls[index+k].m_steer,
|
||||
m_all_controls[index+k].m_accel,
|
||||
m_all_controls[index+k].getSteer(),
|
||||
m_all_controls[index+k].getAccel(),
|
||||
m_all_controls[index+k].getButtonsCompressed(),
|
||||
m_all_xyz[index+k].getX(), m_all_xyz[index+k].getY(),
|
||||
m_all_xyz[index+k].getZ(),
|
||||
@ -314,6 +311,11 @@ void History::Load()
|
||||
sscanf(s, "delta: %f\n",&m_all_deltas[i]);
|
||||
}
|
||||
|
||||
// We need to disable the rewind manager here (otherwise setting the
|
||||
// KartControl data would access the rewind manager).
|
||||
bool rewind_manager_was_enabled = RewindManager::isEnabled();
|
||||
RewindManager::setEnable(false);
|
||||
|
||||
for(int i=0; i<m_size; i++)
|
||||
{
|
||||
for(unsigned int k=0; k<num_karts; k++)
|
||||
@ -321,19 +323,21 @@ void History::Load()
|
||||
unsigned int index = num_karts * i+k;
|
||||
fgets(s, 1023, fd);
|
||||
int buttonsCompressed;
|
||||
float x,y,z,rx,ry,rz,rw;
|
||||
float x,y,z,rx,ry,rz,rw, steer, accel;
|
||||
sscanf(s, "%f %f %d %f %f %f %f %f %f %f\n",
|
||||
&m_all_controls[index].m_steer,
|
||||
&m_all_controls[index].m_accel,
|
||||
&buttonsCompressed,
|
||||
&steer, &accel, &buttonsCompressed,
|
||||
&x, &y, &z,
|
||||
&rx, &ry, &rz, &rw
|
||||
);
|
||||
m_all_controls[index].setSteer(steer);
|
||||
m_all_controls[index].setAccel(accel);
|
||||
m_all_xyz[index] = Vec3(x,y,z);
|
||||
m_all_rotations[index] = btQuaternion(rx,ry,rz,rw);
|
||||
m_all_controls[index].setButtonsCompressed(char(buttonsCompressed));
|
||||
} // for i
|
||||
} // for k
|
||||
RewindManager::setEnable(rewind_manager_was_enabled);
|
||||
|
||||
fprintf(fd, "History file end.\n");
|
||||
fclose(fd);
|
||||
} // Load
|
||||
|
@ -77,26 +77,21 @@ private:
|
||||
std::vector<std::string> m_kart_ident;
|
||||
|
||||
void allocateMemory(int number_of_frames);
|
||||
void updateSaving(float dt);
|
||||
void updateReplay(float dt);
|
||||
public:
|
||||
History ();
|
||||
void startReplay ();
|
||||
void initRecording ();
|
||||
void update (float dt);
|
||||
void Save ();
|
||||
void Load ();
|
||||
void updateSaving(float dt);
|
||||
float updateReplayAndGetDT();
|
||||
|
||||
// -------------------I-----------------------------------------------------
|
||||
/** Returns the identifier of the n-th kart. */
|
||||
const std::string& getKartIdent(unsigned int n)
|
||||
{
|
||||
return m_kart_ident[n];
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the size of the next timestep. */
|
||||
float getNextDelta () const { return m_all_deltas[m_current]; }
|
||||
|
||||
} // getKartIdent
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns if a history is replayed, i.e. the history mode is not none. */
|
||||
bool replayHistory () const { return m_replay_mode != HISTORY_NONE; }
|
||||
|
@ -378,7 +378,7 @@ namespace Scripting
|
||||
Log::error("Scripting", "The script ended with an exception.");
|
||||
|
||||
// Write some information about the script exception
|
||||
asIScriptFunction *func = ctx->GetExceptionFunction();
|
||||
//asIScriptFunction *func = ctx->GetExceptionFunction();
|
||||
//std::cout << "func: " << func->GetDeclaration() << std::endl;
|
||||
//std::cout << "modl: " << func->GetModuleName() << std::endl;
|
||||
//std::cout << "sect: " << func->GetScriptSectionName() << std::endl;
|
||||
@ -520,7 +520,6 @@ namespace Scripting
|
||||
{
|
||||
if (m_callback_delegate != NULL)
|
||||
{
|
||||
asIScriptEngine* engine = World::getWorld()->getScriptEngine()->getEngine();
|
||||
m_callback_delegate->Release();
|
||||
}
|
||||
}
|
||||
|
@ -975,8 +975,6 @@ bool CScriptArray::Less(const void *a, const void *b, bool asc, asIScriptContext
|
||||
}
|
||||
else
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
if( subTypeId & asTYPEID_OBJHANDLE )
|
||||
{
|
||||
// Allow sort to work even if the array contains null handles
|
||||
@ -988,7 +986,7 @@ bool CScriptArray::Less(const void *a, const void *b, bool asc, asIScriptContext
|
||||
if( cache && cache->cmpFunc )
|
||||
{
|
||||
// TODO: Add proper error handling
|
||||
r = ctx->Prepare(cache->cmpFunc); assert(r >= 0);
|
||||
int r = ctx->Prepare(cache->cmpFunc); assert(r >= 0);
|
||||
|
||||
if( subTypeId & asTYPEID_OBJHANDLE )
|
||||
{
|
||||
|
@ -215,7 +215,7 @@ void CreditsScreen::loadedFromFile()
|
||||
|
||||
|
||||
irr::core::stringw translators_credits = _("translator-credits");
|
||||
const int MAX_PER_SCREEN = 6;
|
||||
const unsigned MAX_PER_SCREEN = 6;
|
||||
|
||||
if (translators_credits != L"translator-credits")
|
||||
{
|
||||
|
@ -177,8 +177,6 @@ void EditTrackScreen::init()
|
||||
// -----------------------------------------------------------------------------
|
||||
void EditTrackScreen::loadTrackList()
|
||||
{
|
||||
bool belongs_to_group;
|
||||
|
||||
DynamicRibbonWidget* tracks_widget = getWidget<DynamicRibbonWidget>("tracks");
|
||||
assert(tracks_widget != NULL);
|
||||
|
||||
@ -187,7 +185,7 @@ void EditTrackScreen::loadTrackList()
|
||||
for (unsigned int i = 0; i < track_manager->getNumberOfTracks(); i++)
|
||||
{
|
||||
Track* t = track_manager->getTrack(i);
|
||||
belongs_to_group = (m_track_group.empty() ||
|
||||
bool belongs_to_group = (m_track_group.empty() ||
|
||||
m_track_group == ALL_TRACKS_GROUP_ID ||
|
||||
t->isInGroup(m_track_group) );
|
||||
if (!t->isArena() && !t->isSoccer() &&
|
||||
|
@ -1158,13 +1158,12 @@ void KartSelectionScreen::allPlayersDone()
|
||||
if (selected_kart == RANDOM_KART_ID)
|
||||
{
|
||||
// don't select an already selected kart
|
||||
int random_id;
|
||||
// to prevent infinite loop in case they are all locked
|
||||
int count = 0;
|
||||
bool done = false;
|
||||
do
|
||||
{
|
||||
random_id = random.get(item_count);
|
||||
int random_id = random.get(item_count);
|
||||
// valid kart if it can bt used, and is either not locked,
|
||||
// or it's a multiplayer race.
|
||||
if (items[random_id].m_code_name != ID_DONT_USE &&
|
||||
|
@ -621,11 +621,10 @@ bool OptionsScreenDevice::conflictsBetweenKbdConfig(PlayerAction action,
|
||||
PlayerAction from,
|
||||
PlayerAction to)
|
||||
{
|
||||
KeyboardConfig* other_kbd_config;
|
||||
int id = m_config->getBinding(action).getId();
|
||||
for (int i=0; i < input_manager->getDeviceManager()->getKeyboardAmount(); i++)
|
||||
{
|
||||
other_kbd_config =
|
||||
KeyboardConfig* other_kbd_config =
|
||||
input_manager->getDeviceManager()->getKeyboardConfig(i);
|
||||
|
||||
if (m_config != other_kbd_config &&
|
||||
|
@ -604,7 +604,7 @@ void RaceGUI::drawEnergyMeter(int x, int y, const AbstractKart *kart,
|
||||
|
||||
|
||||
video::SMaterial m;
|
||||
if(kart->getControls().m_nitro || kart->isOnMinNitroTime())
|
||||
if(kart->getControls().getNitro() || kart->isOnMinNitroTime())
|
||||
m.setTexture(0, m_gauge_full_bright);
|
||||
else
|
||||
m.setTexture(0, m_gauge_full);
|
||||
|
@ -241,7 +241,6 @@ void ServerSelection::onUpdate(float dt)
|
||||
|
||||
m_server_list_widget->clear();
|
||||
|
||||
ServersManager *manager = ServersManager::get();
|
||||
loadList();
|
||||
m_server_list_widget->addItem("spacer", L"");
|
||||
m_server_list_widget->addItem("loading",
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "irrlicht.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
/** Constructor for a checkline.
|
||||
@ -171,7 +172,7 @@ bool CheckLine::isTriggered(const Vec3 &old_pos, const Vec3 &new_pos,
|
||||
|
||||
bool previous_sign;
|
||||
|
||||
if (kart_index == -1)
|
||||
if (kart_index == UINT_MAX)
|
||||
{
|
||||
core::vector2df p = old_pos.toIrrVector2d();
|
||||
previous_sign = (m_line.getPointOrientation(p) >= 0);
|
||||
@ -212,10 +213,10 @@ bool CheckLine::isTriggered(const Vec3 &old_pos, const Vec3 &new_pos,
|
||||
else
|
||||
result = false;
|
||||
|
||||
if (kart_index != -1)
|
||||
if (kart_index != UINT_MAX)
|
||||
m_previous_sign[kart_index] = sign;
|
||||
|
||||
if (result && kart_index != -1)
|
||||
if (result && kart_index != UINT_MAX)
|
||||
{
|
||||
LinearWorld* lw = dynamic_cast<LinearWorld*>(w);
|
||||
if (lw != NULL)
|
||||
|
Loading…
x
Reference in New Issue
Block a user