Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

@@ -188,9 +188,9 @@
<powerup collect-mode="new"/>
<!-- time: How long a switch is being effective.
items for each item list the index of the item it is switched with.
Order: giftbox, banana, big-nitro, small-nitro, bubble-gum, trigger,
nolok-bubble-gum, easter egg -->
<switch time="5" items="1 0 4 4 2 5 2 7"/>
Order: giftbox, banana, big-nitro, small-nitro, bubble-gum, nolok-bubble-gum,
easter egg, trigger-->
<switch time="5" items="1 0 4 4 2 2 6 7"/>

<!-- disappear-counter: How often bubblegum gets driven over before it disappears.
shield-time: How long the bubblegum shield lasts
@@ -206,8 +206,13 @@
steering-reduction: Reduce a remote kart's steering by this factor
each frame. This helps reduces oversteering by high latency
clients when they only do minor steering adjustments.
max-moveable-objects: Maximum number of moveable objects in a track
when networking is on. Objects will be hidden if total count is
larger than this value.
-->
<networking state-frequency="10" steering-reduction="1.0"/>
<networking state-frequency="10"
steering-reduction="1.0"
max-moveable-objects="15"/>

<!-- The field od views for 1-4 player split screen. fov-3 is
actually not used (since 3 player split screen uses the
@@ -541,6 +546,14 @@
<!-- List of default ports used, by default STK use random ports for client.
The server discovery port has to be the same across all clients and servers.
-->
<network server-discovery-port="2757" client-port="2758" server-port="2759"/>
<network-ports server-discovery-port="2757" client-port="2758" server-port="2759"/>

<!-- Configurable values used in SmoothNetworkBody class.
-->
<network-smoothing min-adjust-length="0.1"
max-adjust-length="4.0"
min-adjust-speed="0.3"
max-adjust-time="2.0"
adjust-length-threshold="4.0"/>

</config>
@@ -16,9 +16,6 @@ namespace irr
namespace video
{

// Static members
io::path CImageLoaderJPG::Filename;

//! constructor
CImageLoaderJPG::CImageLoaderJPG()
{
@@ -108,10 +105,10 @@ void CImageLoaderJPG::error_exit (j_common_ptr cinfo)
void CImageLoaderJPG::output_message(j_common_ptr cinfo)
{
// display the error message.
c8 temp1[JMSG_LENGTH_MAX];
(*cinfo->err->format_message)(cinfo, temp1);
core::stringc errMsg("JPEG FATAL ERROR in ");
errMsg += core::stringc(Filename);
//c8 temp1[JMSG_LENGTH_MAX];
//(*cinfo->err->format_message)(cinfo, temp1);
//core::stringc errMsg("JPEG FATAL ERROR in ");
//errMsg += core::stringc(Filename);
//os::Printer::log(errMsg.c_str(),temp1, ELL_ERROR);
}
#endif // _IRR_COMPILE_WITH_LIBJPEG_
@@ -145,8 +142,6 @@ IImage* CImageLoaderJPG::loadImage(io::IReadFile* file, bool skip_checking) cons
if (!file)
return 0;

Filename = file->getFileName();

u8 **rowPtr=0;
u8* input = new u8[file->getSize()];
file->read(input, file->getSize());
@@ -100,9 +100,6 @@ class CImageLoaderJPG : public IImageLoader
data has been read. Often a no-op. */
static void term_source (j_decompress_ptr cinfo);

// Copy filename to have it around for error-messages
static io::path Filename;

#endif // _IRR_COMPILE_WITH_LIBJPEG_
};

@@ -123,6 +123,7 @@ MusicInformation::MusicInformation(const XMLNode *root,

MusicInformation::~MusicInformation()
{
std::lock_guard<std::mutex> lock(m_music_mutex);
if(m_normal_music) delete m_normal_music;
if(m_fast_music) delete m_fast_music;
} // ~MusicInformation
@@ -146,6 +147,7 @@ void MusicInformation::startMusic()
m_time_since_faster = 0.0f;
m_mode = SOUND_NORMAL;

std::unique_lock<std::mutex> lock(m_music_mutex);
if (m_normal_music)
{
delete m_normal_music;
@@ -180,9 +182,11 @@ void MusicInformation::startMusic()
{
m_normal_music = new MusicDummy();
}
lock.unlock();

if (m_normal_music->load(m_normal_filename) == false)
{
lock.lock();
delete m_normal_music;
m_normal_music = NULL;
Log::warn("MusicInformation", "Unable to load music %s, "
@@ -206,6 +210,7 @@ void MusicInformation::startMusic()
return;
}

lock.lock();
#ifdef ENABLE_SOUND
if (UserConfigParams::m_enable_sound)
{
@@ -216,9 +221,11 @@ void MusicInformation::startMusic()
{
m_fast_music = new MusicDummy();
}
lock.unlock();

if (m_fast_music->load(m_fast_filename) == false)
{
lock.lock();
delete m_fast_music;
m_fast_music = NULL;
Log::warn("MusicInformation", "Unabled to load fast music %s, not "
@@ -281,6 +288,7 @@ void MusicInformation::update(float dt)
//-----------------------------------------------------------------------------
void MusicInformation::stopMusic()
{
std::lock_guard<std::mutex> lock(m_music_mutex);
if (m_normal_music != NULL)
{
m_normal_music->stopMusic();
@@ -357,6 +365,7 @@ void MusicInformation::switchToFastMusic()

bool MusicInformation::isPlaying() const
{
std::lock_guard<std::mutex> lock(m_music_mutex);
return (m_normal_music != NULL && m_normal_music->isPlaying()) ||
(m_fast_music != NULL && m_fast_music->isPlaying());
}
@@ -19,6 +19,7 @@
#ifndef HEADER_MUSIC_INFORMATION_HPP
#define HEADER_MUSIC_INFORMATION_HPP

#include <mutex>
#include <string>
#include <stdexcept>
#include <vector>
@@ -66,6 +67,7 @@ class MusicInformation : public NoCopy
/** Maximum pitch for faster music. */
float m_max_pitch;
static const int LOOP_FOREVER=-1;
mutable std::mutex m_music_mutex;
Music *m_normal_music,
*m_fast_music;
enum {SOUND_NORMAL, //!< normal music is played
@@ -38,7 +38,7 @@ MusicOggStream::MusicOggStream(float loop_start)
m_soundBuffers[0] = m_soundBuffers[1]= 0;
m_soundSource = -1;
m_pausedMusic = true;
m_playing = false;
m_playing.store(false);
m_loop_start = loop_start;
} // MusicOggStream

@@ -168,7 +168,7 @@ bool MusicOggStream::release()
if(!m_error) ov_clear(&m_oggStream);

m_soundSource = -1;
m_playing = false;
m_playing.store(false);

return true;
} // release
@@ -189,15 +189,15 @@ bool MusicOggStream::playMusic()

alSourcePlay(m_soundSource);
m_pausedMusic = false;
m_playing = true;
m_playing.store(true);
check("playMusic");
return true;
} // playMusic

//-----------------------------------------------------------------------------
bool MusicOggStream::isPlaying()
{
return m_playing;
return m_playing.load();

/*
if (m_soundSource == -1) return false;
@@ -212,14 +212,14 @@ bool MusicOggStream::isPlaying()
//-----------------------------------------------------------------------------
bool MusicOggStream::stopMusic()
{
m_playing = false;
m_playing.store(false);
return (release());
} // stopMusic

//-----------------------------------------------------------------------------
bool MusicOggStream::pauseMusic()
{
m_playing = false;
m_playing.store(false);
if (m_fileName == "")
{
// nothing is loaded
@@ -234,7 +234,7 @@ bool MusicOggStream::pauseMusic()
//-----------------------------------------------------------------------------
bool MusicOggStream::resumeMusic()
{
m_playing = true;
m_playing.store(true);

if (m_fileName == "")
{
@@ -40,6 +40,8 @@
#endif
#include "audio/music.hpp"

#include <atomic>

/**
* \brief ogg files based implementation of the Music interface
* \ingroup audio
@@ -78,7 +80,7 @@ class MusicOggStream : public Music
vorbis_info* m_vorbisInfo;
bool m_error;

bool m_playing;
std::atomic_bool m_playing;

ALuint m_soundBuffers[2];
ALuint m_soundSource;
@@ -35,6 +35,7 @@

#include <stdio.h>
#include <stdlib.h>
#include <limits>
#include <math.h>

#ifdef ENABLE_SOUND
@@ -88,7 +89,7 @@ SFXManager::SFXManager()
// The sound manager initialises OpenAL
m_initialized = music_manager->initialized();
m_master_gain = UserConfigParams::m_sfx_volume;
m_last_update_time = -1.0f;
m_last_update_time = std::numeric_limits<uint64_t>::max();
// Init position, since it can be used before positionListener is called.
// No need to use lock here, since the thread will be created later.
m_listener_position.getData() = Vec3(0, 0, 0);
@@ -477,10 +478,10 @@ void* SFXManager::mainLoop(void *obj)
{
// Wait some time to let other threads run, then queue an
// update event to keep music playing.
double t = StkTime::getRealTime();
uint64_t t = StkTime::getRealTimeMs();
StkTime::sleep(1);
t = StkTime::getRealTime() - t;
me->queue(SFX_UPDATE, (SFXBase*)NULL, float(t));
t = StkTime::getRealTimeMs() - t;
me->queue(SFX_UPDATE, (SFXBase*)NULL, float(t / 1000.0));
}
me->m_sfx_commands.lock();
PROFILER_POP_CPU_MARKER();
@@ -833,16 +834,16 @@ void SFXManager::reallyUpdateNow(SFXCommand *current)
#ifdef ENABLE_SOUND
if (!UserConfigParams::m_enable_sound)
return;
if (m_last_update_time < 0.0)

if (m_last_update_time == std::numeric_limits<uint64_t>::max())
{
// first time
m_last_update_time = StkTime::getRealTime();
m_last_update_time = StkTime::getRealTimeMs();
}

double previous_update_time = m_last_update_time;
m_last_update_time = StkTime::getRealTime();
float dt = float(m_last_update_time - previous_update_time);
uint64_t previous_update_time = m_last_update_time;
m_last_update_time = StkTime::getRealTimeMs();
float dt = float(m_last_update_time - previous_update_time) / 1000.0f;

assert(current->m_command==SFX_UPDATE);
if (music_manager->getCurrentMusic())
@@ -218,7 +218,7 @@ class SFXManager : public NoCopy, public CanBeDeleted
/** Thread id of the thread running in this object. */
Synchronised<pthread_t *> m_thread_id;

double m_last_update_time;
uint64_t m_last_update_time;

/** A conditional variable to wake up the main loop. */
pthread_cond_t m_cond_request;
@@ -253,6 +253,9 @@ void UnlockManager::findWhatWasUnlocked(int points_before, int points_now,
std::vector<std::string>& karts,
std::vector<const ChallengeData*>& unlocked)
{
if (UserConfigParams::m_unlock_everything > 0)
return;

ChallengeData* c = NULL;

for (AllChallengesType::iterator it = m_all_challenges.begin();
@@ -152,11 +152,16 @@ void STKConfig::load(const std::string &filename)
CHECK_NEG(m_default_track_friction, "physics default-track-friction");
CHECK_NEG(m_physics_fps, "physics fps" );
CHECK_NEG(m_network_state_frequeny, "network state-frequency" );
CHECK_NEG(m_max_moveable_objects, "network max-moveable-objects");
CHECK_NEG(m_network_steering_reduction,"network steering-reduction" );
CHECK_NEG(m_default_moveable_friction, "physics default-moveable-friction");
CHECK_NEG(m_solver_iterations, "physics: solver-iterations" );
CHECK_NEG(m_network_state_frequeny, "network solver-state-frequency" );
CHECK_NEG(m_solver_split_impulse_thresh,"physics: solver-split-impulse-threshold");
CHECK_NEG(m_snb_min_adjust_length, "network smoothing: min-adjust-length");
CHECK_NEG(m_snb_max_adjust_length, "network smoothing: max-adjust-length");
CHECK_NEG(m_snb_min_adjust_speed, "network smoothing: min-adjust-speed");
CHECK_NEG(m_snb_max_adjust_time, "network smoothing: max-adjust-time");
CHECK_NEG(m_snb_adjust_length_threshold, "network smoothing: adjust-length-threshold");

// Square distance to make distance checks cheaper (no sqrt)
m_default_kart_properties->checkAllSet(filename);
@@ -199,6 +204,7 @@ void STKConfig::init_defaults()
m_donate_url = "";
m_password_reset_url = "";
m_network_state_frequeny = -100;
m_max_moveable_objects = -100;
m_solver_iterations = -100;
m_solver_set_flags = 0;
m_solver_reset_flags = 0;
@@ -216,6 +222,9 @@ void STKConfig::init_defaults()
m_server_discovery_port = 2757;
m_client_port = 2758;
m_server_port = 2759;
m_snb_min_adjust_length = m_snb_max_adjust_length =
m_snb_min_adjust_speed = m_snb_max_adjust_time =
m_snb_adjust_length_threshold = UNDEFINED;

m_score_increase.clear();
m_leader_intervals.clear();
@@ -436,6 +445,7 @@ void STKConfig::getAllData(const XMLNode * root)
if (const XMLNode *networking_node = root->getNode("networking"))
{
networking_node->get("state-frequency", &m_network_state_frequeny);
networking_node->get("max-moveable-objects", &m_max_moveable_objects);
networking_node->get("steering-reduction", &m_network_steering_reduction);
}

@@ -477,19 +487,28 @@ void STKConfig::getAllData(const XMLNode * root)
tc->get("quality", &m_tc_quality);
}

if (const XMLNode *tc = root->getNode("network"))
if (const XMLNode *np = root->getNode("network-ports"))
{
unsigned server_discovery_port = 0;
unsigned client_port = 0;
unsigned server_port = 0;
tc->get("server-discovery-port", &server_discovery_port);
tc->get("client-port", &client_port);
tc->get("server-port", &server_port);
np->get("server-discovery-port", &server_discovery_port);
np->get("client-port", &client_port);
np->get("server-port", &server_port);
m_server_discovery_port = (uint16_t)server_discovery_port;
m_client_port = (uint16_t)client_port;
m_server_port = (uint16_t)server_port;
}

if (const XMLNode *ns = root->getNode("network-smoothing"))
{
ns->get("min-adjust-length", &m_snb_min_adjust_length);
ns->get("max-adjust-length", &m_snb_max_adjust_length);
ns->get("min-adjust-speed", &m_snb_min_adjust_speed);
ns->get("max-adjust-time", &m_snb_max_adjust_time);
ns->get("adjust-length-threshold", &m_snb_adjust_length_threshold);
}

// Get the default KartProperties
// ------------------------------
const XMLNode *node = root -> getNode("general-kart-defaults");
@@ -89,6 +89,9 @@ class STKConfig : public NoCopy
/** How many state updates per second the server will send. */
int m_network_state_frequeny;

/** Maximum number of moveable objects in a track when networking is on. */
int m_max_moveable_objects;

/** In case of a network race, remote karts will get their steering somewhat
* reduced each frame. This reduces stutter when a kart only does small
* steering adjustments. */
@@ -203,6 +206,11 @@ class STKConfig : public NoCopy
std::vector<std::string> m_normal_ttf;
std::vector<std::string> m_digit_ttf;

/** Configurable values used in SmoothNetworkBody class. */
float m_snb_min_adjust_length, m_snb_max_adjust_length,
m_snb_min_adjust_speed, m_snb_max_adjust_time,
m_snb_adjust_length_threshold;

private:
/** True if stk_config has been loaded. This is necessary if the
* --stk-config command line parameter has been specified to avoid
@@ -498,17 +498,21 @@ namespace UserConfigParams
&m_multitouch_group,
"Multitouch mode: 0 = undefined, 1 = steering wheel, 2 = accelerometer, 3 = gyroscope"));

PARAM_PREFIX FloatUserConfigParam m_multitouch_deadzone_center
PARAM_DEFAULT( FloatUserConfigParam(0.1f, "multitouch_deadzone_center",
PARAM_PREFIX FloatUserConfigParam m_multitouch_deadzone
PARAM_DEFAULT( FloatUserConfigParam(0.1f, "multitouch_deadzone",
&m_multitouch_group,
"A parameter in range [0, 0.5] that determines the zone that is "
"considered as centered in steering button."));

PARAM_PREFIX FloatUserConfigParam m_multitouch_deadzone_edge
PARAM_DEFAULT( FloatUserConfigParam(0.1f, "multitouch_deadzone_edge",
PARAM_PREFIX FloatUserConfigParam m_multitouch_sensitivity_x
PARAM_DEFAULT( FloatUserConfigParam(0.1f, "multitouch_sensitivity_x",
&m_multitouch_group,
"A parameter in range [0, 0.5] that determines the zone that is "
"considered as max value in steering button."));
"A parameter in range [0, 1.0] that determines the sensitivity for x axis."));

PARAM_PREFIX FloatUserConfigParam m_multitouch_sensitivity_y
PARAM_DEFAULT( FloatUserConfigParam(0.65f, "multitouch_sensitivity_y",
&m_multitouch_group,
"A parameter in range [0, 1.0] that determines the sensitivity for y axis."));

PARAM_PREFIX FloatUserConfigParam m_multitouch_tilt_factor
PARAM_DEFAULT( FloatUserConfigParam(4.0f, "multitouch_tilt_factor",
@@ -20,6 +20,7 @@

#include "karts/abstract_kart.hpp"
#include "karts/kart_properties.hpp"
#include "race/race_manager.hpp"
#include "tracks/drive_graph.hpp"

#include "ICameraSceneNode.h"
@@ -57,6 +58,8 @@ void CameraEnd::clearEndCameras()
void CameraEnd::readEndCamera(const XMLNode &root)
{
m_end_cameras.clear();
if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_EASTER_EGG)
return;
for(unsigned int i=0; i<root.getNumNodes(); i++)
{
unsigned int index = i;
@@ -343,8 +343,12 @@ void DynamicRibbonWidget::buildInternalStructure()

// ---- determine column amount
const float row_height = (float)(m_h - m_label_height)/(float)m_row_amount;
float ratio_zoom = (float)row_height / (float)(m_child_height - m_label_height);
m_col_amount = (int)roundf( m_w / ( m_child_width*ratio_zoom ) );
float col_width = (float)(row_height * m_child_width / m_child_height);

// Give some margin for columns for better readability
col_width *= 1.2f;

m_col_amount = (int)floor( m_w / col_width );

// ajust column amount to not add more item slots than we actually need
const int item_count = (int) m_items.size();
@@ -173,7 +173,7 @@ void MultitouchDevice::reset()
}

m_orientation = 0.0f;
m_gyro_time = 0.0;
m_gyro_time = 0;
} // reset

// ----------------------------------------------------------------------------
@@ -223,7 +223,9 @@ void MultitouchDevice::activateGyroscope()
#ifdef ANDROID
if (!m_android_device->isGyroscopeActive())
{
m_android_device->activateGyroscope(1.0f / 60); // Assume 60 FPS, some phones can do 90 and 120 FPS but we won't handle them now
// Assume 60 FPS, some phones can do 90 and 120 FPS but we won't handle
// them now
m_android_device->activateGyroscope(1.0f / 60);
}
#endif
}
@@ -350,26 +352,33 @@ void MultitouchDevice::updateDeviceState(unsigned int event_id)
*/
void MultitouchDevice::updateConfigParams()
{
m_deadzone_center = UserConfigParams::m_multitouch_deadzone_center;
m_deadzone_center = std::min(std::max(m_deadzone_center, 0.0f), 0.5f);
m_deadzone = UserConfigParams::m_multitouch_deadzone;
m_deadzone = std::min(std::max(m_deadzone, 0.0f), 0.5f);

m_deadzone_edge = UserConfigParams::m_multitouch_deadzone_edge;
m_deadzone_edge = std::min(std::max(m_deadzone_edge, 0.0f), 0.5f);
m_sensitivity_x = UserConfigParams::m_multitouch_sensitivity_x;
m_sensitivity_x = std::min(std::max(m_sensitivity_x, 0.0f), 1.0f);

m_sensitivity_y = UserConfigParams::m_multitouch_sensitivity_y;
m_sensitivity_y = std::min(std::max(m_sensitivity_y, 0.0f), 1.0f);
} // updateConfigParams

// ----------------------------------------------------------------------------
/** Helper function that returns a steering factor for steering button.
* \param value The axis value from 0 to 1.
* \param sensitivity Value from 0 to 1.0.
*/
float MultitouchDevice::getSteeringFactor(float value)
float MultitouchDevice::getSteeringFactor(float value, float sensitivity)
{
if (m_deadzone_edge + m_deadzone_center >= 1.0f)
if (m_deadzone >= 1.0f)
return 0.0f;

if (sensitivity >= 1.0f)
return 1.0f;

assert(m_deadzone_edge + m_deadzone_center != 1.0f);

return std::min((value - m_deadzone_center) / (1.0f - m_deadzone_edge -
m_deadzone_center), 1.0f);
float factor = (value - m_deadzone) / (1.0f - m_deadzone);
factor *= 1.0f / (1.0f - sensitivity);

return std::min(factor, 1.0f);
}

// ----------------------------------------------------------------------------
@@ -379,15 +388,15 @@ void MultitouchDevice::updateAxisX(float value)
if (m_controller == NULL)
return;

if (value < -m_deadzone_center)
if (value < -m_deadzone)
{
float factor = getSteeringFactor(std::abs(value));
float factor = getSteeringFactor(std::abs(value), m_sensitivity_x);
m_controller->action(PA_STEER_RIGHT, 0);
m_controller->action(PA_STEER_LEFT, int(factor * Input::MAX_VALUE));
}
else if (value > m_deadzone_center)
else if (value > m_deadzone)
{
float factor = getSteeringFactor(std::abs(value));
float factor = getSteeringFactor(std::abs(value), m_sensitivity_x);
m_controller->action(PA_STEER_LEFT, 0);
m_controller->action(PA_STEER_RIGHT, int(factor * Input::MAX_VALUE));
}
@@ -405,26 +414,28 @@ void MultitouchDevice::updateAxisY(float value)
if (m_controller == NULL)
return;

if (value < -m_deadzone_center)
if (value < -m_deadzone)
{
float factor = getSteeringFactor(std::abs(value));
float factor = getSteeringFactor(std::abs(value), m_sensitivity_y);
m_controller->action(PA_ACCEL, int(factor * Input::MAX_VALUE));
}
else if (value > m_deadzone_center)
else if (value > m_deadzone)
{
float factor = getSteeringFactor(std::abs(value));
float factor = getSteeringFactor(std::abs(value), m_sensitivity_y);
m_controller->action(PA_BRAKE, int(factor * Input::MAX_VALUE));
}
else
{
m_controller->action(PA_BRAKE, 0);
m_controller->action(PA_ACCEL, 0);
}

}

// ----------------------------------------------------------------------------

/** Returns device orientation Z angle, in radians, where 0 is landscape orientation parallel to the floor.
/** Returns device orientation Z angle, in radians, where 0 is landscape
* orientation parallel to the floor.
*/
float MultitouchDevice::getOrientation()
{
@@ -441,14 +452,14 @@ float MultitouchDevice::getOrientation()
void MultitouchDevice::updateOrientationFromAccelerometer(float x, float y)
{
const float ACCEL_DISCARD_THRESHOLD = 4.0f;
const float ACCEL_MULTIPLIER = 0.05f; // Slowly adjust the angle over time, this prevents shaking
const float ACCEL_MULTIPLIER = 0.05f; // Slowly adjust the angle over time,
// this prevents shaking
const float ACCEL_CHANGE_THRESHOLD = 0.01f; // ~0.5 degrees

// The device is flat on the table, cannot reliably determine the
// orientation
if (fabsf(x) + fabsf(y) < ACCEL_DISCARD_THRESHOLD)
{
// The device is flat on the table, cannot reliably determine the orientation
return;
}

float angle = atan2f(y, x);
if (angle > (M_PI / 2.0))
@@ -473,7 +484,8 @@ void MultitouchDevice::updateOrientationFromAccelerometer(float x, float y)

m_orientation += delta;

//Log::warn("Accel", "X %03.4f Y %03.4f angle %03.4f delta %03.4f orientation %03.4f", x, y, angle, delta, m_orientation);
//Log::warn("Accel", "X %03.4f Y %03.4f angle %03.4f delta %03.4f "
// "orientation %03.4f", x, y, angle, delta, m_orientation);
}

// ----------------------------------------------------------------------------
@@ -486,9 +498,10 @@ void MultitouchDevice::updateOrientationFromGyroscope(float z)
{
const float GYRO_SPEED_THRESHOLD = 0.005f;

double now = StkTime::getRealTime();
float timedelta = now - m_gyro_time;
uint64_t now = StkTime::getRealTimeMs();
uint64_t delta = now - m_gyro_time;
m_gyro_time = now;
float timedelta = (float)delta / 1000.f;
if (timedelta > 0.5f)
{
timedelta = 0.1f;
@@ -511,7 +524,9 @@ void MultitouchDevice::updateOrientationFromGyroscope(float z)
m_orientation = -(M_PI / 2.0);
}

//Log::warn("Gyro", "Z %03.4f angular_speed %03.4f delta %03.4f orientation %03.4f", z, angular_speed, angular_speed * timedelta, m_orientation);
//Log::warn("Gyro", "Z %03.4f angular_speed %03.4f delta %03.4f "
// "orientation %03.4f", z, angular_speed,
// angular_speed * timedelta, m_orientation);
}

// ----------------------------------------------------------------------------
@@ -23,6 +23,7 @@
#include <vector>

#include "input/input_device.hpp"
#include "utils/types.hpp"
#include "IEventReceiver.h"

#ifdef ANDROID
@@ -81,21 +82,23 @@ class MultitouchDevice : public InputDevice

/** The parameter that is used for steering button and determines dead area
* in a center of button */
float m_deadzone_center;
float m_deadzone;

/** The parameter that is used for steering button and determines dead area
* at the edge of button */
float m_deadzone_edge;
/** A parameter in range that determines the sensitivity for x axis. */
float m_sensitivity_x;

/** A parameter in range that determines the sensitivity for y axis. */
float m_sensitivity_y;

float m_orientation;
double m_gyro_time;
uint64_t m_gyro_time;

#ifdef ANDROID
/** Pointer to the Android irrlicht device */
CIrrDeviceAndroid* m_android_device;
#endif

float getSteeringFactor(float value);
float getSteeringFactor(float value, float sensitivity);
void handleControls(MultitouchButton* button);
bool isGameRunning();

@@ -70,7 +70,7 @@ void ItemState::setDisappearCounter()
m_used_up_counter = -1;
} // switch
} // setDisappearCounter

// -----------------------------------------------------------------------
/** Initialises an item.
* \param type Type for this item.
@@ -157,24 +157,21 @@ Item::Item(ItemType type, const Vec3& xyz, const Vec3& normal,
m_was_available_previously = true;
m_distance_2 = 1.2f;
initItem(type, xyz);

m_graphical_type = type;
m_original_rotation = shortestArcQuat(Vec3(0, 1, 0), normal);
m_rotation_angle = 0.0f;
m_original_mesh = mesh;
m_original_lowmesh = lowres_mesh;
m_listener = NULL;

LODNode* lodnode =
LODNode* lodnode =
new LODNode("item", irr_driver->getSceneManager()->getRootSceneNode(),
irr_driver->getSceneManager());
scene::ISceneNode* meshnode =
scene::ISceneNode* meshnode =
irr_driver->addMesh(mesh, StringUtils::insertValues("item_%i", (int)type));

if (lowres_mesh != NULL)
{
lodnode->add(35, meshnode, true);
scene::ISceneNode* meshnode =
irr_driver->addMesh(lowres_mesh,
scene::ISceneNode* meshnode =
irr_driver->addMesh(lowres_mesh,
StringUtils::insertValues("item_lo_%i", (int)type));
lodnode->add(100, meshnode, true);
}
@@ -184,6 +181,7 @@ Item::Item(ItemType type, const Vec3& xyz, const Vec3& normal,
}
m_node = lodnode;
setType(type);
handleNewMesh(getType());

#ifdef DEBUG
std::string debug_name("item: ");
@@ -209,10 +207,8 @@ Item::Item(const Vec3& xyz, float distance, TriggerItemListener* trigger)
{
m_distance_2 = distance*distance;
initItem(ITEM_TRIGGER, xyz);
m_graphical_type = ITEM_TRIGGER;
m_original_rotation = btQuaternion(0, 0, 0, 1);
m_rotation_angle = 0.0f;
m_original_mesh = NULL;
m_original_lowmesh = NULL;
m_node = NULL;
m_listener = trigger;
m_was_available_previously = true;
@@ -226,8 +222,6 @@ Item::Item(const Vec3& xyz, float distance, TriggerItemListener* trigger)
void Item::initItem(ItemType type, const Vec3 &xyz)
{
ItemState::initItem(type, xyz);
m_rotate = (getType()!=ITEM_BUBBLEGUM) &&
(getType()!=ITEM_TRIGGER );
// Now determine in which quad this item is, and its distance
// from the center within this quad.
m_graph_node = Graph::UNKNOWN_SECTOR;
@@ -258,68 +252,13 @@ void Item::initItem(ItemType type, const Vec3 &xyz)

} // initItem

//-----------------------------------------------------------------------------
/** Sets the type of the item (and also derived attributes lile m_rotate
* \param type Type of the item.
*/
void Item::setType(ItemType type)
{
ItemState::setType(type);
m_rotate = (type!=ITEM_BUBBLEGUM) && (type!=ITEM_TRIGGER);

if (m_node != NULL)
{
for (auto* node : m_node->getAllNodes())
{
SP::SPMeshNode* spmn = dynamic_cast<SP::SPMeshNode*>(node);
if (spmn)
{
spmn->setGlowColor(ItemManager::get()->getGlowColor(type));
}
}
}
} // setType

//-----------------------------------------------------------------------------
/** Changes this item to be a new type for a certain amount of time.
* \param type New type of this item.
* \param mesh Mesh to use to display this item.
*/
void Item::switchTo(ItemType type, scene::IMesh *mesh, scene::IMesh *lowmesh)
{
setMesh(mesh, lowmesh);
ItemState::switchTo(type, mesh, lowmesh);
} // switchTo

//-----------------------------------------------------------------------------
/** Switch backs to the original item. Returns true if the item wa snot
* actually switched (e.g. trigger, or bubblegum dropped during switch
* time). The return value is not actually used, but necessary in order
* to overwrite ItemState::switchBack()
*/
bool Item::switchBack()
{
setMesh(m_original_mesh, m_original_lowmesh);

if (ItemState::switchBack())
return true;

if (m_node != NULL)
{
Vec3 hpr;
hpr.setHPR(m_original_rotation);
m_node->setRotation(hpr.toIrrHPR());
}
return false;
} // switchBack

//-----------------------------------------------------------------------------
void Item::setMesh(scene::IMesh* mesh, scene::IMesh* lowres_mesh)
{
#ifndef SERVER_ONLY
if (m_node == NULL)
return;

unsigned i = 0;
for (auto* node : m_node->getAllNodes())
{
@@ -365,14 +304,35 @@ void Item::reset()
{
m_was_available_previously = true;
ItemState::reset();

if (m_node != NULL)
{
m_node->setScale(core::vector3df(1,1,1));
m_node->setVisible(true);
}

} // reset

// ----------------------------------------------------------------------------
void Item::handleNewMesh(ItemType type)
{
#ifndef SERVER_ONLY
if (m_node == NULL)
return;
setMesh(ItemManager::get()->getItemModel(type),
ItemManager::get()->getItemLowResolutionModel(type));
for (auto* node : m_node->getAllNodes())
{
SP::SPMeshNode* spmn = dynamic_cast<SP::SPMeshNode*>(node);
if (spmn)
spmn->setGlowColor(ItemManager::get()->getGlowColor(type));
}
Vec3 hpr;
hpr.setHPR(m_original_rotation);
m_node->setRotation(hpr.toIrrHPR());
#endif
} // handleNewMesh

// ----------------------------------------------------------------------------
/** Updated the item - rotates it, takes care of items coming back into
* the game after it has been collected.
@@ -383,9 +343,15 @@ void Item::updateGraphics(float dt)
if (m_node == NULL)
return;

if (m_graphical_type != getType())
{
handleNewMesh(getType());
m_graphical_type = getType();
}

float time_till_return = stk_config->ticks2Time(getTicksTillReturn());
bool is_visible = isAvailable() || time_till_return <= 1.0f ||
(getType() == ITEM_BUBBLEGUM &&
bool is_visible = isAvailable() || time_till_return <= 1.0f ||
(getType() == ITEM_BUBBLEGUM &&
getOriginalType() == ITEM_NONE && !isUsedUp());

m_node->setVisible(is_visible);
@@ -400,40 +366,37 @@ void Item::updateGraphics(float dt)
if (!isAvailable() && time_till_return <= 1.0f)
{
// Make it visible by scaling it from 0 to 1:
if (rotating())
{
float angle =
fmodf((float)(World::getWorld()->getTicksSinceStart() +
getTicksTillReturn()) / 40.0f, M_PI * 2);
btMatrix3x3 m;
m.setRotation(m_original_rotation);
btQuaternion r = btQuaternion(m.getColumn(1), angle) *
m_original_rotation;
Vec3 hpr;
hpr.setHPR(r);
m_node->setRotation(hpr.toIrrHPR());
}
m_node->setVisible(true);
m_node->setScale(core::vector3df(1, 1, 1)*(1 - time_till_return));
}
if (isAvailable() && m_rotate)
if (isAvailable() && rotating())
{
// have it rotate
m_rotation_angle += dt * M_PI;
if (m_rotation_angle > M_PI * 2) m_rotation_angle -= M_PI * 2;
float angle =
fmodf((float)World::getWorld()->getTicksSinceStart() / 40.0f,
M_PI * 2);

btMatrix3x3 m;
m.setRotation(m_original_rotation);
btQuaternion r = btQuaternion(m.getColumn(1), m_rotation_angle) *
btQuaternion r = btQuaternion(m.getColumn(1), angle) *
m_original_rotation;

Vec3 hpr;
hpr.setHPR(r);
m_node->setRotation(hpr.toIrrHPR());
} // if item is available
m_was_available_previously = isAvailable();
} // update

//-----------------------------------------------------------------------------
/** Is called when the item is hit by a kart. It sets the flag that the item
* has been collected, and the time to return to the parameter.
* \param kart The kart that collected the item.
*/
void Item::collected(const AbstractKart *kart)
{
ItemState::collected(kart);

if (m_listener != NULL)
{
m_listener->onTriggerItemApproached();
}

} // isCollected

} // updateGraphics
@@ -202,7 +202,7 @@ class ItemState

// -----------------------------------------------------------------------
/** Resets an item to its start state. */
void reset()
virtual void reset()
{
m_deactive_ticks = 0;
m_ticks_till_return = 0;
@@ -219,11 +219,8 @@ class ItemState
/** Switches an item to be of a different type. Used for the switch
* powerup.
* \param type New type for this item.
* \param mesh Ignored.
* \param lowmesh Ignored.
*/
virtual void switchTo(ItemType type, scene::IMesh *mesh,
scene::IMesh *lowmesh)
virtual void switchTo(ItemType type)
{
// triggers and easter eggs should not be switched
if (m_type == ITEM_TRIGGER || m_type == ITEM_EASTER_EGG) return;
@@ -326,18 +323,11 @@ class Item : public ItemState, public NoCopy
* rotation). */
btQuaternion m_original_rotation;

/** Used when rotating the item */
float m_rotation_angle;

/** Scene node of this item. */
LODNode *m_node;

/** Stores the original mesh in order to reset it. */
scene::IMesh *m_original_mesh;
scene::IMesh *m_original_lowmesh;

/** Set to false if item should not rotate. */
bool m_rotate;
/** Graphical type of the mesh. */
ItemType m_graphical_type;

/** Stores if the item was available in the previously rendered frame. */
bool m_was_available_previously;
@@ -360,9 +350,9 @@ class Item : public ItemState, public NoCopy
* would not be collected. Used by the AI to avoid items. */
Vec3 *m_avoidance_points[2];

void setType(ItemType type) OVERRIDE;
void initItem(ItemType type, const Vec3 &xyz);
void setMesh(scene::IMesh* mesh, scene::IMesh* lowres_mesh);
void handleNewMesh(ItemType type);

public:
Item(ItemType type, const Vec3& xyz, const Vec3& normal,
@@ -373,12 +363,31 @@ class Item : public ItemState, public NoCopy
TriggerItemListener* trigger);
virtual ~Item ();
virtual void updateGraphics(float dt) OVERRIDE;
virtual void collected(const AbstractKart *kart) OVERRIDE;
void reset();
virtual void switchTo(ItemType type, scene::IMesh *mesh,
scene::IMesh *lowmesh) OVERRIDE;
virtual bool switchBack() OVERRIDE;
virtual void reset() OVERRIDE;

//-------------------------------------------------------------------------
/** Is called when the item is hit by a kart. It sets the flag that the
* item has been collected, and the time to return to the parameter.
* \param kart The kart that collected the item.
*/
virtual void collected(const AbstractKart *kart) OVERRIDE
{
ItemState::collected(kart);
if (m_listener != NULL)
m_listener->onTriggerItemApproached();
} // isCollected
//-------------------------------------------------------------------------
/** Switch backs to the original item. Returns true if the item was not
* actually switched (e.g. trigger, or bubblegum dropped during switch
* time). The return value is not actually used, but necessary in order
* to overwrite ItemState::switchBack()
*/
virtual bool switchBack() OVERRIDE
{
if (ItemState::switchBack())
return true;
return false;
} // switchBack
// ------------------------------------------------------------------------
/** Returns true if the Kart is close enough to hit this item, the item is
* not deactivated anymore, and it wasn't placed by this kart (this is
@@ -397,6 +406,9 @@ class Item : public ItemState, public NoCopy
lc.setY(lc.getY() / 2.0f);
return lc.length2() < m_distance_2;
} // hitKart
// ------------------------------------------------------------------------
bool rotating() const
{ return getType() != ITEM_BUBBLEGUM && getType() != ITEM_TRIGGER; }

public:
// ------------------------------------------------------------------------
@@ -53,6 +53,7 @@ ItemEventInfo::ItemEventInfo(BareNetworkString *buffer, int *count)
} // is not switch
else // switch
{
m_index = -1;
m_kart_id = -1;
}
} // ItemEventInfo(BareNetworkString, int *count)
@@ -307,8 +307,7 @@ Item* ItemManager::dropNewItem(ItemState::ItemType type,
if(m_switch_ticks>=0)
{
ItemState::ItemType new_type = m_switch_to[item->getType()];
item->switchTo(new_type, m_item_mesh[(int)new_type],
m_item_lowres_mesh[(int)new_type]);
item->switchTo(new_type);
}
return item;
} // dropNewItem
@@ -338,8 +337,7 @@ Item* ItemManager::placeItem(ItemState::ItemType type, const Vec3& xyz,
if (m_switch_ticks >= 0)
{
ItemState::ItemType new_type = m_switch_to[item->getType()];
item->switchTo(new_type, m_item_mesh[(int)new_type],
m_item_lowres_mesh[(int)new_type]);
item->switchTo(new_type);
}
return item;
} // placeItem
@@ -575,8 +573,7 @@ void ItemManager::switchItemsInternal(std::vector<ItemState*> &all_items)
if (new_type == (*i)->getType())
continue;
if(m_switch_ticks<0)
(*i)->switchTo(new_type, m_item_mesh[(int)new_type],
m_item_lowres_mesh[(int)new_type]);
(*i)->switchTo(new_type);
else
(*i)->switchBack();
} // for all_items
@@ -45,22 +45,17 @@ class ItemManager : public NoCopy
{
// Some static data and functions to initialise it:
private:
/** Stores all item models. */
static std::vector<scene::IMesh *> m_item_mesh;

/** Stores the glow color for all items. */
static std::vector<video::SColorf> m_glow_color;

/** Stores all low-resolution item models. */
static std::vector<scene::IMesh *> m_item_lowres_mesh;

/** Disable item collection (for debugging purposes). */
static bool m_disable_item_collection;

static std::mt19937 m_random_engine;
protected:
/** The instance of ItemManager while a race is on. */
static std::shared_ptr<ItemManager> m_item_manager;

public:
static void loadDefaultItemMeshes();
static void removeTextures();
@@ -84,6 +79,10 @@ class ItemManager : public NoCopy
static scene::IMesh* getItemModel(ItemState::ItemType type)
{ return m_item_mesh[type]; }
// ------------------------------------------------------------------------
/** Returns the low resolution mesh for a certain item. */
static scene::IMesh* getItemLowResolutionModel(ItemState::ItemType type)
{ return m_item_lowres_mesh[type]; }
// ------------------------------------------------------------------------
/** Returns the glow color for an item. */
static video::SColorf& getGlowColor(ItemState::ItemType type)
{ return m_glow_color[type]; }
@@ -102,14 +101,20 @@ class ItemManager : public NoCopy
typedef std::vector<ItemState*> AllItemTypes;
AllItemTypes m_all_items;

/** What item this item is switched to. */
std::vector<ItemState::ItemType> m_switch_to;

private:
/** Stores which items are on which quad. m_items_in_quads[#quads]
* contains all items that are not on a quad. Note that this
* field is undefined if no Graph exist, e.g. arena without navmesh. */
std::vector< AllItemTypes > *m_items_in_quads;

/** What item this item is switched to. */
std::vector<ItemState::ItemType> m_switch_to;
/** Stores all item models. */
static std::vector<scene::IMesh *> m_item_mesh;

/** Stores all low-resolution item models. */
static std::vector<scene::IMesh *> m_item_lowres_mesh;

protected:
/** Remaining time that items should remain switched. If the
@@ -371,7 +371,8 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count)
iei.getIndex(),
iei.getTicks(), iei.isItemCollection(), iei.isNewItem(),
iei.getTicksTillReturn(),
iei.getIndex() < (int)m_confirmed_state.size() ? m_confirmed_state[iei.getIndex()] : NULL);
iei.getIndex() < (int)m_confirmed_state.size() && iei.getIndex() != -1 ?
m_confirmed_state[iei.getIndex()] : NULL);
// 1.2) If the event needs to be applied, forward
// the time to the time of this event:
// ----------------------------------------------
@@ -409,6 +410,11 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count)
ItemState *is = new ItemState(iei.getNewItemType(), kart,
iei.getIndex() );
is->initItem(iei.getNewItemType(), iei.getXYZ());
if (m_switch_ticks >= 0)
{
ItemState::ItemType new_type = m_switch_to[is->getType()];
is->switchTo(new_type);
}

// A new confirmed item must either be inserted at the end of all
// items, or in an existing unused entry.
@@ -478,8 +484,6 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count)
? m_confirmed_state[i] : NULL;
if (is && item)
{
// TODO: Check that the item has the right model, otherwise it
// might be an incorrectly predicted item.
*(ItemState*)item = *is;
}
else if (is && !item)
@@ -281,6 +281,15 @@ int MaxSpeed::getSpeedIncreaseTicksLeft(unsigned int category)
return m_speed_increase[category].getTimeLeft();
} // getSpeedIncreaseTimeLeft

// ----------------------------------------------------------------------------
/** Returns if increased speed is active in the given category.
* \param category Which category to report on.
*/
int MaxSpeed::isSpeedIncreaseActive(unsigned int category)
{
return m_speed_increase[category].isActive();
} // isSpeedIncreaseActive

// ----------------------------------------------------------------------------
/** Returns if decreased speed is active in the given category.
* \param category Which category to report on.
@@ -192,6 +192,7 @@ friend class KartRewinder;
void setSlowdown(unsigned int category, float max_speed_fraction,
int fade_in_time, int duration=-1);
int getSpeedIncreaseTicksLeft(unsigned int category);
int isSpeedIncreaseActive(unsigned int category);
int isSpeedDecreaseActive(unsigned int category);
void update(int ticks);
void reset();
@@ -82,6 +82,7 @@ void Skidding::reset()
m_graphical_remaining_jump_time = 0.0f;
m_smoothing_time = 0.0f;
m_smoothing_dt = -1.0f;
m_skid_bonus_end_ticks = -1;

btVector3 rot(0, 0, 0);
// Only access the vehicle if the kart is not a ghost
@@ -255,6 +256,54 @@ float Skidding::getSteeringWhenSkidding(float steering) const
*/
float Skidding::updateGraphics(float dt)
{
m_kart->getKartGFX()->setCreationRateAbsolute(KartGFX::KGFX_SKIDL, 0);
m_kart->getKartGFX()->setCreationRateAbsolute(KartGFX::KGFX_SKIDR, 0);
m_kart->getKartGFX()->updateSkidLight(0);

float bonus_time, bonus_speed, bonus_force;
unsigned int level = getSkidBonus(&bonus_time, &bonus_speed, &bonus_force);
if (m_kart->m_max_speed
->isSpeedIncreaseActive(MaxSpeed::MS_INCREASE_SKIDDING) &&
m_skid_bonus_end_ticks > World::getWorld()->getTicksSinceStart())
{
level = 1;
}
else if (m_kart->m_max_speed
->isSpeedIncreaseActive(MaxSpeed::MS_INCREASE_RED_SKIDDING) &&
m_skid_bonus_end_ticks > World::getWorld()->getTicksSinceStart())
{
level = 2;
}

if (level == 0 && m_graphical_remaining_jump_time <= 0.0f &&
m_skid_state != SKID_NONE)
{
// Show tiny sparks if bonus not yet reached
m_kart->getKartGFX()->setSkidLevel(level);
}
else if (level >= 1)
{
// If at least level 1 bonus is reached, show appropriate gfx
m_kart->getKartGFX()->setSkidLevel(level);
m_kart->getKartGFX()->updateSkidLight(level);
}

if (bonus_time > 0 || level == 1 || level == 2)
{
m_kart->getKartGFX()->setCreationRateRelative(KartGFX::KGFX_SKIDL,
1.0f);
m_kart->getKartGFX()->setCreationRateRelative(KartGFX::KGFX_SKIDR,
1.0f);
}
else if (m_skid_state == SKID_BREAK || m_skid_state == SKID_SHOW_GFX_LEFT
|| m_skid_state == SKID_SHOW_GFX_RIGHT)
{
m_kart->getKartGFX()->setCreationRateAbsolute(KartGFX::KGFX_SKIDL,
0.0f);
m_kart->getKartGFX()->setCreationRateAbsolute(KartGFX::KGFX_SKIDR,
0.0f);
}

if (m_smoothing_dt >= 0.0f)
{
m_smoothing_dt += dt / m_smoothing_time;
@@ -321,8 +370,6 @@ void Skidding::update(int ticks, bool is_on_ground,
m_skid_state != SKID_NONE && m_skid_state != SKID_BREAK)
{
m_skid_state = SKID_BREAK;
m_kart->getKartGFX()->setCreationRateAbsolute(KartGFX::KGFX_SKIDL, 0);
m_kart->getKartGFX()->setCreationRateAbsolute(KartGFX::KGFX_SKIDR, 0);
}

m_skid_bonus_ready = false;
@@ -473,15 +520,9 @@ void Skidding::update(int ticks, bool is_on_ground,
unsigned int level = getSkidBonus(&bonus_time, &bonus_speed,
&bonus_force);

// Show tiny sparks if bonus not yet reached
if (level == 0 && m_remaining_jump_time <= 0.0f)
m_kart->getKartGFX()->setSkidLevel(level);
// If at least level 1 bonus is reached, show appropriate gfx
else if (level>=1)
if (level >= 1 && !(level == 0 && m_remaining_jump_time <= 0.0f))
{
m_skid_bonus_ready = true;
m_kart->getKartGFX()->setSkidLevel(level);
m_kart->getKartGFX()->updateSkidLight(level);
}
// If player stops skidding, trigger bonus, and change state to
// SKID_SHOW_GFX_*
@@ -500,10 +541,6 @@ void Skidding::update(int ticks, bool is_on_ground,
m_skid_time = stk_config->time2Ticks(t);
if(bonus_time>0)
{
m_kart->getKartGFX()
->setCreationRateRelative(KartGFX::KGFX_SKIDL, 1.0f);
m_kart->getKartGFX()
->setCreationRateRelative(KartGFX::KGFX_SKIDR, 1.0f);
unsigned int bonus_cat = (level == 1) ? MaxSpeed::MS_INCREASE_SKIDDING :
MaxSpeed::MS_INCREASE_RED_SKIDDING;
m_kart->m_max_speed->
@@ -513,6 +550,9 @@ void Skidding::update(int ticks, bool is_on_ground,
stk_config->time2Ticks(bonus_time),
/*fade-out-time*/ stk_config->time2Ticks(1.0f));

m_skid_bonus_end_ticks = World::getWorld()->getTicksSinceStart() +
stk_config->time2Ticks(1.0f);

if (m_kart->getController()->canGetAchievements())
{
PlayerManager::increaseAchievement(
@@ -523,12 +563,10 @@ void Skidding::update(int ticks, bool is_on_ground,
AchievementsStatus::SKIDDING, 1);
}
}
else {
m_kart->getKartGFX()
->setCreationRateAbsolute(KartGFX::KGFX_SKIDL, 0);
m_kart->getKartGFX()
->setCreationRateAbsolute(KartGFX::KGFX_SKIDR, 0);
}
else
{
m_skid_bonus_end_ticks = -1;
}
}
break;
} // case
@@ -538,11 +576,6 @@ void Skidding::update(int ticks, bool is_on_ground,
m_skid_time -= ticks;
if (m_skid_time == 0)
{
m_kart->getKartGFX()
->setCreationRateAbsolute(KartGFX::KGFX_SKIDL, 0);
m_kart->getKartGFX()
->setCreationRateAbsolute(KartGFX::KGFX_SKIDR, 0);
m_kart->getKartGFX()->updateSkidLight(0);
m_skid_state = SKID_NONE;
}
} // switch
@@ -75,6 +75,8 @@ friend class KartRewinder;

float m_smoothing_dt;

int m_skid_bonus_end_ticks;

public:
/** SKID_NONE: Kart is currently not skidding.
* SKID_ACCUMULATE_LEFT: Kart is skidding to the left and accumulating
@@ -221,6 +221,7 @@ void EasterEggHunt::reset(bool restart)
for(unsigned int i=0; i<m_eggs_collected.size(); i++)
m_eggs_collected[i] = 0;
m_eggs_found = 0;
m_finish_time = 0;
} // reset

//-----------------------------------------------------------------------------
@@ -122,7 +122,6 @@ void SoccerWorld::init()
Log::fatal("SoccerWorld","Ball is missing in soccer field, abort.");

m_bgd.init(m_ball->getPhysicalObject()->getRadius());
m_ball_body->setActivationState(DISABLE_DEACTIVATION);

} // init

@@ -184,7 +184,7 @@ void WorldStatus::update(int ticks)
*/
void WorldStatus::updateTime(int ticks)
{
switch (m_phase)
switch (m_phase.load())
{
// Note: setup phase must be a separate phase, since the race_manager
// checks the phase when updating the camera: in the very first time
@@ -265,6 +265,10 @@ void WorldStatus::updateTime(int ticks)
}
return; // Don't increase time
case WAIT_FOR_SERVER_PHASE:
{
return; // Don't increase time
}
case SERVER_READY_PHASE:
{
auto lobby = LobbyProtocol::get<LobbyProtocol>();
if (lobby && lobby->isRacing())
@@ -19,6 +19,7 @@
#define HEADER_WORLD_STATUS_HPP

#include "utils/cpp2011.hpp"
#include <atomic>

class SFXBase;

@@ -49,6 +50,9 @@ class WorldStatus
// 'start'. This happens on a network client only
WAIT_FOR_SERVER_PHASE,

// Used in network games only: server is ready
SERVER_READY_PHASE,

// 'Ready' is displayed
READY_PHASE,

@@ -111,7 +115,7 @@ class WorldStatus
protected:
bool m_play_track_intro_sound;
bool m_play_ready_set_go_sounds;
Phase m_phase;
std::atomic<Phase> m_phase;

private:

@@ -808,6 +808,7 @@ void ClientLobby::connectionRefused(Event* event)
*/
void ClientLobby::startGame(Event* event)
{
World::getWorld()->setPhase(WorldStatus::SERVER_READY_PHASE);
uint64_t start_time = event->data().getUInt64();
joinStartGameThread();
m_start_game_thread = std::thread([start_time, this]()
@@ -183,13 +183,13 @@ void GameEventsProtocol::kartFinishedRace(const NetworkString &ns)

uint8_t kart_id = ns.getUInt8();
float time = ns.getFloat();
World::getWorld()->getKart(kart_id)->finishedRace(time,
/*from_server*/true);
if (race_manager->modeHasLaps())
{
World::getWorld()->getKart(kart_id)
->setPosition(m_last_finished_position++);
}
World::getWorld()->getKart(kart_id)->finishedRace(time,
/*from_server*/true);
} // kartFinishedRace

// ----------------------------------------------------------------------------
@@ -2330,9 +2330,9 @@ void ServerLobby::configPeersStartTime()
}
max_ping = std::max(peer->getAveragePing(), max_ping);
}
// Start up time will be after 2000ms, so even if this packet is sent late
// Start up time will be after 2500ms, so even if this packet is sent late
// (due to packet loss), the start time will still ahead of current time
uint64_t start_time = STKHost::get()->getNetworkTimer() + (uint64_t)2000;
uint64_t start_time = STKHost::get()->getNetworkTimer() + (uint64_t)2500;
NetworkString* ns = getNetworkString(10);
ns->addUInt8(LE_START_RACE).addUInt64(start_time);
sendMessageToPeers(ns, /*reliable*/true);
@@ -2347,6 +2347,7 @@ void ServerLobby::configPeersStartTime()
delete ns;
m_state = WAIT_FOR_RACE_STARTED;

World::getWorld()->setPhase(WorldStatus::SERVER_READY_PHASE);
joinStartGameThread();
m_start_game_thread = std::thread([start_time, this]()
{
@@ -17,9 +17,24 @@
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

#include "network/smooth_network_body.hpp"
#include "config/stk_config.hpp"

#include <algorithm>

// ----------------------------------------------------------------------------
SmoothNetworkBody::SmoothNetworkBody(bool enable)
{
reset();
m_enabled = enable;
m_smooth_rotation = true;
m_adjust_vertical_offset = true;
m_min_adjust_length = stk_config->m_snb_min_adjust_length;
m_max_adjust_length = stk_config->m_snb_max_adjust_length;
m_min_adjust_speed = stk_config->m_snb_min_adjust_speed;
m_max_adjust_time = stk_config->m_snb_max_adjust_time;
m_adjust_length_threshold = stk_config->m_snb_adjust_length_threshold;
} // SmoothNetworkBody

// ----------------------------------------------------------------------------
void SmoothNetworkBody::prepareSmoothing(const btTransform& current_transform,
const Vec3& current_velocity)
@@ -58,7 +73,7 @@ void SmoothNetworkBody::checkSmoothing(const btTransform& current_transform,
if (speed < m_min_adjust_speed)
return;

float adjust_time = (adjust_length * 2.0f) / speed;
float adjust_time = (adjust_length * m_adjust_length_threshold) / speed;
if (adjust_time > m_max_adjust_time)
return;

@@ -68,20 +68,10 @@ class SmoothNetworkBody
bool m_adjust_vertical_offset;

float m_min_adjust_length, m_max_adjust_length, m_min_adjust_speed,
m_max_adjust_time;
m_max_adjust_time, m_adjust_length_threshold;

public:
SmoothNetworkBody(bool enable = false)
{
reset();
m_enabled = enable;
m_smooth_rotation = true;
m_adjust_vertical_offset = true;
m_min_adjust_length = 0.1f;
m_max_adjust_length = 4.0f;
m_min_adjust_speed = 0.3f;
m_max_adjust_time = 2.0f;
}
SmoothNetworkBody(bool enable = false);
// ------------------------------------------------------------------------
virtual ~SmoothNetworkBody() {}
// ------------------------------------------------------------------------
@@ -128,6 +118,9 @@ class SmoothNetworkBody
void setMinAdjustSpeed(float val) { m_min_adjust_speed = val; }
// ------------------------------------------------------------------------
void setMaxAdjustTime(float val) { m_max_adjust_time = val; }
// ------------------------------------------------------------------------
void setAdjustLengthThreshold(float val)
{ m_adjust_length_threshold = val; }

};

@@ -519,7 +519,8 @@ class RaceManager
return (unsigned int)m_ai_kart_list.size();
} // getNumberOfAIKarts
// ------------------------------------------------------------------------
unsigned int getNumNonGhostKarts() const { return m_num_karts - m_num_ghost_karts; }
unsigned int getNumNonGhostKarts() const
{ return m_num_karts - m_num_ghost_karts; }
// ------------------------------------------------------------------------
MajorRaceModeType getMajorMode() const { return m_major_mode; }
// ------------------------------------------------------------------------
@@ -37,29 +37,41 @@ using namespace Online;

// ----------------------------------------------------------------------------
AchievementProgressDialog::AchievementProgressDialog(Achievement *achievement)
: ModalDialog(0.9f,0.9f), m_achievement(achievement),
: ModalDialog(0.95f,0.92f), m_achievement(achievement),
m_self_destroy(false)
{
loadFromFile("online/achievement_progress_dialog.stkgui");
m_progress_table = getWidget<ListWidget>("progress-tree");
assert(m_progress_table != NULL);


m_depth = m_achievement->getInfo()->getDepth();
assert (m_depth < 3);

m_progress_table = getWidget<ListWidget>("progress-tree");
assert(m_progress_table != NULL);
m_progress_table->clear();

std::vector<ListWidget::ListCell> row;
for (int i=0;i<m_depth;i++)

m_main_goal_description = getWidget<LabelWidget>("main-goal-description");
assert(m_main_goal_description != NULL);

m_main_goal_progress = getWidget<LabelWidget>("main-goal-progress");
assert(m_main_goal_progress != NULL);

if (m_depth > 1)
{
row.push_back(ListWidget::ListCell
(_C("achievement_info", "Goal"), -1, 2, true));
row.push_back(ListWidget::ListCell
(_C("achievement_info", "Progress"), -1, 1, true));
std::vector<ListWidget::ListCell> row;
for (int i = 1; i < m_depth; i++)
{
row.push_back(ListWidget::ListCell
(_C("achievement_info", "Subgoals"), -1, 2, true));
row.push_back(ListWidget::ListCell
(_C("achievement_info", "Progress"), -1, 1, true));
}

m_progress_table->addItem(StringUtils::toString(0), row);
}

m_progress_table->addItem(StringUtils::toString(0), row);

m_row_counter = 1;
recursiveFillTable(m_achievement->m_progress_goal_tree, m_achievement->m_achievement_info->m_goal_tree, 0);
recursiveFillTable(m_achievement->m_progress_goal_tree,
m_achievement->m_achievement_info->m_goal_tree, 0);
} // AchievementProgressDialog

// -----------------------------------------------------------------------------
@@ -86,35 +98,50 @@ void AchievementProgressDialog::recursiveFillTable(AchievementInfo::goalTree &pr
}

if (m_achievement->isAchieved() || goal > target)
{
goal = target;

std::vector<ListWidget::ListCell> row;
for (int i=0;i<m_depth;i++)
}
if (depth == 0)
{
//TODO : for sum, indicate if a subgoal counts towards or against it
if (i==depth)
{
std::string temp = StringUtils::toString(goal) + "/" +
StringUtils::toString(target);
core::stringw progress_string(temp.c_str());
core::stringw goal_name = niceGoalName(progress.type);
row.push_back(ListWidget::ListCell
(goal_name, -1, 2, true));
row.push_back(ListWidget::ListCell
(progress_string, -1, 1, true));
}
else
std::string temp = StringUtils::toString(goal) + "/" +
StringUtils::toString(target);
core::stringw progress_string(temp.c_str());
core::stringw goal_name = niceGoalName(progress.type);

m_main_goal_description->setText(goal_name, false);
m_main_goal_progress->setText(progress_string, false);
}
else
{
std::vector<ListWidget::ListCell> row;
for (int i = 1; i < m_depth; i++)
{
row.push_back(ListWidget::ListCell
(" ", -1, 2, true));
row.push_back(ListWidget::ListCell
(" ", -1, 1, true));
//TODO : for sum, indicate if a subgoal counts towards or against it
if (i == depth)
{
std::string temp = StringUtils::toString(goal) + "/" +
StringUtils::toString(target);
core::stringw progress_string(temp.c_str());
core::stringw goal_name = niceGoalName(progress.type);
row.push_back(ListWidget::ListCell
(goal_name, -1, 2, true));
row.push_back(ListWidget::ListCell
(progress_string, -1, 1, true));
}
else
{
row.push_back(ListWidget::ListCell
(" ", -1, 2, true));
row.push_back(ListWidget::ListCell
(" ", -1, 1, true));
}
}
m_progress_table->addItem(StringUtils::toString(m_row_counter), row);
m_row_counter++;
}
m_progress_table->addItem(StringUtils::toString(m_row_counter), row);
m_row_counter++;

for (unsigned int i=0;i<progress.children.size();i++)
for (unsigned int i = 0; i < progress.children.size(); i++)
{
recursiveFillTable(progress.children[i],reference.children[i],depth+1);
}
@@ -315,7 +342,7 @@ void AchievementProgressDialog::init()
LabelWidget* description = getWidget<LabelWidget>("description");
assert(description != NULL);
core::stringw description_text = m_achievement->getInfo()->getDescription();
description->setText(description_text, true /* expand as needed */);
description->setText(description_text, false);
} // init

// -----------------------------------------------------------------------------
@@ -48,6 +48,8 @@ class AchievementProgressDialog : public GUIEngine::ModalDialog
int m_row_counter;//Used in the recurisve table filling

GUIEngine::ListWidget* m_progress_table;
GUIEngine::LabelWidget* m_main_goal_description;
GUIEngine::LabelWidget* m_main_goal_progress;

GUIEngine::RibbonWidget* m_options_widget;

@@ -25,7 +25,6 @@
#include "graphics/irr_driver.hpp"
#include "graphics/render_info.hpp"
#include "guiengine/engine.hpp"
#include "guiengine/widgets/check_box_widget.hpp"
#include "guiengine/widgets/label_widget.hpp"
#include "guiengine/widgets/model_view_widget.hpp"
#include "guiengine/widgets/spinner_widget.hpp"
@@ -41,14 +40,17 @@ KartColorSliderDialog::KartColorSliderDialog(PlayerProfile* pp)
m_player_profile = pp;

// I18N: In kart color choosing dialog
m_original_color = _("Use original color");
core::stringw original_color = _("Use original color");
// I18N: In kart color choosing dialog
m_choose_color = _("Pick a color from slider");
core::stringw choose_color = _("Pick a color from slider");

m_toggle_slider->clearLabels();
m_toggle_slider->addLabel(original_color);
m_toggle_slider->addLabel(choose_color);

if (m_player_profile->getDefaultKartColor() != 0.0f)
{
m_toggle_slider->setState(true);
m_toggle_text->setText(m_choose_color, false);
m_toggle_slider->setValue(1);
m_color_slider->setActive(true);
m_color_slider->setValue(int(
m_player_profile->getDefaultKartColor() * 100.0f));
@@ -57,8 +59,7 @@ KartColorSliderDialog::KartColorSliderDialog(PlayerProfile* pp)
}
else
{
m_toggle_slider->setState(false);
m_toggle_text->setText(m_original_color, false);
m_toggle_slider->setValue(0);
m_color_slider->setActive(false);
m_model_view->getModelViewRenderInfo()->setHue(0.0f);
}
@@ -148,26 +149,23 @@ void KartColorSliderDialog::beforeAddingWidgets()

m_model_view->setRotateContinuously(35.0f);
m_model_view->update(0);
m_toggle_slider = getWidget<CheckBoxWidget>("toggle-slider");
m_toggle_text = getWidget<LabelWidget>("toggle-text");
m_toggle_slider = getWidget<SpinnerWidget>("toggle-slider");
m_color_slider = getWidget<SpinnerWidget>("color-slider");
} // beforeAddingWidgets

// ----------------------------------------------------------------------------
void KartColorSliderDialog::toggleSlider()
{
if (m_toggle_slider->getState())
if (m_toggle_slider->getValue() == 1)
{
m_color_slider->setActive(true);
m_color_slider->setValue(100);
m_model_view->getModelViewRenderInfo()->setHue(1.0f);
m_toggle_text->setText(m_choose_color, false);
}
else
{
m_color_slider->setActive(false);
m_model_view->getModelViewRenderInfo()->setHue(0.0f);
m_toggle_text->setText(m_original_color, false);
}
} // toggleSlider

@@ -187,7 +185,7 @@ GUIEngine::EventPropagation
else if (eventSource == "close")
{
float color = 0.0f;
if (m_toggle_slider->getState())
if (m_toggle_slider->getValue() == 1)
color = float(m_color_slider->getValue()) / 100.0f;
m_player_profile->setDefaultKartColor(color);
ModalDialog::dismiss();
@@ -26,7 +26,6 @@ class PlayerProfile;
namespace GUIEngine
{
class CheckBoxWidget;
class LabelWidget;
class ModelViewWidget;
class SpinnerWidget;
}
@@ -39,16 +38,12 @@ class KartColorSliderDialog : public GUIEngine::ModalDialog
private:
PlayerProfile* m_player_profile;

GUIEngine::CheckBoxWidget* m_toggle_slider;

GUIEngine::LabelWidget* m_toggle_text;
GUIEngine::SpinnerWidget* m_toggle_slider;

GUIEngine::ModelViewWidget* m_model_view;

GUIEngine::SpinnerWidget* m_color_slider;

core::stringw m_original_color, m_choose_color;

void toggleSlider();
public:
KartColorSliderDialog(PlayerProfile* pp);
@@ -95,15 +95,20 @@ GUIEngine::EventPropagation MultitouchSettingsDialog::processEvent(
assert(scale != NULL);
UserConfigParams::m_multitouch_scale = (float)scale->getValue() / 100.0f;

SpinnerWidget* deadzone_edge = getWidget<SpinnerWidget>("deadzone_edge");
assert(deadzone_edge != NULL);
UserConfigParams::m_multitouch_deadzone_edge =
(float)deadzone_edge->getValue() / 100.0f;

SpinnerWidget* deadzone_center = getWidget<SpinnerWidget>("deadzone_center");
assert(deadzone_center != NULL);
UserConfigParams::m_multitouch_deadzone_center =
(float)deadzone_center->getValue() / 100.0f;
SpinnerWidget* sensitivity_x = getWidget<SpinnerWidget>("sensitivity_x");
assert(sensitivity_x != NULL);
UserConfigParams::m_multitouch_sensitivity_x =
(float)sensitivity_x->getValue() / 100.0f;

SpinnerWidget* sensitivity_y = getWidget<SpinnerWidget>("sensitivity_y");
assert(sensitivity_y != NULL);
UserConfigParams::m_multitouch_sensitivity_y =
(float)sensitivity_y->getValue() / 100.0f;

SpinnerWidget* deadzone = getWidget<SpinnerWidget>("deadzone");
assert(deadzone != NULL);
UserConfigParams::m_multitouch_deadzone =
(float)deadzone->getValue() / 100.0f;

CheckBoxWidget* buttons_en = getWidget<CheckBoxWidget>("buttons_enabled");
assert(buttons_en != NULL);
@@ -146,8 +151,9 @@ GUIEngine::EventPropagation MultitouchSettingsDialog::processEvent(
}
else if (eventSource == "restore")
{
UserConfigParams::m_multitouch_deadzone_edge.revertToDefaults();
UserConfigParams::m_multitouch_deadzone_center.revertToDefaults();
UserConfigParams::m_multitouch_sensitivity_x.revertToDefaults();
UserConfigParams::m_multitouch_sensitivity_y.revertToDefaults();
UserConfigParams::m_multitouch_deadzone.revertToDefaults();
UserConfigParams::m_multitouch_mode.revertToDefaults();
UserConfigParams::m_multitouch_inverted.revertToDefaults();
UserConfigParams::m_multitouch_controls.revertToDefaults();
@@ -204,15 +210,20 @@ void MultitouchSettingsDialog::updateValues()
assert(scale != NULL);
scale->setValue((int)(UserConfigParams::m_multitouch_scale * 100.0f));

SpinnerWidget* deadzone_edge = getWidget<SpinnerWidget>("deadzone_edge");
assert(deadzone_edge != NULL);
deadzone_edge->setValue(
(int)(UserConfigParams::m_multitouch_deadzone_edge * 100.0f));

SpinnerWidget* deadzone_center = getWidget<SpinnerWidget>("deadzone_center");
assert(deadzone_center != NULL);
deadzone_center->setValue(
(int)(UserConfigParams::m_multitouch_deadzone_center * 100.0f));
SpinnerWidget* sensitivity_x = getWidget<SpinnerWidget>("sensitivity_x");
assert(sensitivity_x != NULL);
sensitivity_x->setValue(
(int)(UserConfigParams::m_multitouch_sensitivity_x * 100.0f));

SpinnerWidget* sensitivity_y = getWidget<SpinnerWidget>("sensitivity_y");
assert(sensitivity_y != NULL);
sensitivity_y->setValue(
(int)(UserConfigParams::m_multitouch_sensitivity_y * 100.0f));

SpinnerWidget* deadzone = getWidget<SpinnerWidget>("deadzone");
assert(deadzone != NULL);
deadzone->setValue(
(int)(UserConfigParams::m_multitouch_deadzone * 100.0f));

CheckBoxWidget* buttons_en = getWidget<CheckBoxWidget>("buttons_enabled");
assert(buttons_en != NULL);
@@ -24,6 +24,7 @@
#include "challenges/challenge_data.hpp"
#include "challenges/unlock_manager.hpp"
#include "config/player_manager.hpp"
#include "config/user_config.hpp"
#include "graphics/central_settings.hpp"
#include "graphics/sp/sp_base.hpp"
#include "graphics/sp/sp_mesh.hpp"
@@ -197,6 +198,9 @@ void FeatureUnlockedCutScene::
findWhatWasUnlocked(RaceManager::Difficulty difficulty,
std::vector<const ChallengeData*>& unlocked)
{
if (UserConfigParams::m_unlock_everything > 0)
return;

PlayerProfile *player = PlayerManager::getCurrentPlayer();

// The number of points is updated before this function is called
@@ -191,7 +191,6 @@ RaceGUI::RaceGUI()
//createMarkerTexture();

// Load icon textures for later reuse
m_lap_flag = irr_driver->getTexture(FileManager::GUI_ICON, "lap_flag.png");
m_red_team = irr_driver->getTexture(FileManager::GUI_ICON, "soccer_ball_red.png");
m_blue_team = irr_driver->getTexture(FileManager::GUI_ICON, "soccer_ball_blue.png");
m_red_flag = irr_driver->getTexture(FileManager::GUI_ICON, "red_flag.png");
@@ -93,7 +93,6 @@ class RaceGUI : public RaceGUIBase

/** Icon textures (stored as variables to not look up
their location on every frame) */
irr::video::ITexture *m_lap_flag;
irr::video::ITexture *m_red_team;
irr::video::ITexture *m_blue_team;
irr::video::ITexture *m_red_flag;
@@ -43,6 +43,7 @@
#include "modes/capture_the_flag.hpp"
#include "modes/linear_world.hpp"
#include "modes/world.hpp"
#include "network/network_config.hpp"
#include "states_screens/race_gui_multitouch.hpp"
#include "tracks/track.hpp"
#include "utils/constants.hpp"
@@ -95,10 +96,11 @@ RaceGUIBase::RaceGUIBase()
"Can't find 'icons-frame.png' texture, aborting.");
}

m_gauge_full = irr_driver->getTexture(file_manager->getAsset(FileManager::GUI_ICON,"gauge_full.png"));
m_gauge_full_bright = irr_driver->getTexture(file_manager->getAsset(FileManager::GUI_ICON,"gauge_full_bright.png"));
m_gauge_empty = irr_driver->getTexture(file_manager->getAsset(FileManager::GUI_ICON,"gauge_empty.png"));
m_gauge_goal = irr_driver->getTexture(file_manager->getAsset(FileManager::GUI_ICON,"gauge_goal.png" ));
m_gauge_full = irr_driver->getTexture(FileManager::GUI_ICON, "gauge_full.png");
m_gauge_full_bright = irr_driver->getTexture(FileManager::GUI_ICON, "gauge_full_bright.png");
m_gauge_empty = irr_driver->getTexture(FileManager::GUI_ICON, "gauge_empty.png");
m_gauge_goal = irr_driver->getTexture(FileManager::GUI_ICON, "gauge_goal.png");
m_lap_flag = irr_driver->getTexture(FileManager::GUI_ICON, "lap_flag.png");
m_dist_show_overlap = 2;
m_icons_inertia = 2;

@@ -434,7 +436,15 @@ void RaceGUIBase::update(float dt)
m_referee_height += dt*5.0f;
m_referee->selectReadySetGo(2);
}
else if(world->getPhase()==World::TRACK_INTRO_PHASE)
else if (world->getPhase()==World::WAIT_FOR_SERVER_PHASE ||
(NetworkConfig::get()->isNetworking() &&
world->getPhase()==World::TRACK_INTRO_PHASE))
{
}
else if ((!NetworkConfig::get()->isNetworking() &&
world->getPhase()==World::TRACK_INTRO_PHASE) ||
(NetworkConfig::get()->isNetworking() &&
world->getPhase()==World::SERVER_READY_PHASE))
{
m_referee->selectReadySetGo(0); // set red color
m_referee_height -= dt*5.0f;
@@ -1039,6 +1049,18 @@ void RaceGUIBase::drawPlayerIcon(AbstractKart *kart, int x, int y, int w)
NULL, true);
}
}

//lap flag for finished karts
if (kart->hasFinishedRace())
{
if (m_lap_flag != NULL)
{
const core::rect<s32> rect(core::position2d<s32>(0, 0),
m_lap_flag->getSize());
const core::rect<s32> pos1(x - 20, y - 10, x + w - 20, y + w - 10);
draw2DImage(m_lap_flag, pos1, rect, NULL, NULL, true);
}
}
#endif
} // drawPlayerIcon

@@ -186,6 +186,9 @@ class RaceGUIBase

/** The frame around player karts in the mini map. */
video::ITexture* m_icons_frame;

/** Texture for the lap icon*/
video::ITexture* m_lap_flag;

RaceGUIMultitouch* m_multitouch_gui;

@@ -23,7 +23,6 @@
#include "guiengine/widgets/bubble_widget.hpp"
#include "guiengine/widgets/button_widget.hpp"
#include "guiengine/widgets/spinner_widget.hpp"
#include "guiengine/widgets/check_box_widget.hpp"
#include "guiengine/widgets/label_widget.hpp"
#include "guiengine/widgets/model_view_widget.hpp"
#include "guiengine/scalable_font.hpp"
@@ -90,8 +89,8 @@ void SoccerSetupScreen::eventCallback(Widget* widget, const std::string& name,
}
else if(name == "time_enabled")
{
CheckBoxWidget* timeEnabled = dynamic_cast<CheckBoxWidget*>(widget);
bool timed = timeEnabled->getState();
SpinnerWidget* timeEnabled = dynamic_cast<SpinnerWidget*>(widget);
bool timed = timeEnabled->getValue() == 0;
UserConfigParams::m_soccer_use_time_limit = timed;
getWidget<SpinnerWidget>("goalamount")->setActive(!timed);
getWidget<SpinnerWidget>("timeamount")->setActive(timed);
@@ -226,8 +225,11 @@ void SoccerSetupScreen::init()
timeAmount->setValue(UserConfigParams::m_soccer_time_limit);
timeAmount->setActive(UserConfigParams::m_soccer_use_time_limit);

CheckBoxWidget* timeEnabled = getWidget<CheckBoxWidget>("time_enabled");
timeEnabled->setState(UserConfigParams::m_soccer_use_time_limit);
SpinnerWidget* timeEnabled = getWidget<SpinnerWidget>("time_enabled");
timeEnabled->clearLabels();
timeEnabled->addLabel(_("Time limit"));
timeEnabled->addLabel(_("Goals limit"));
timeEnabled->setValue(UserConfigParams::m_soccer_use_time_limit ? 0 : 1);

// Set focus on "continue"
ButtonWidget* bt_continue = getWidget<ButtonWidget>("continue");
@@ -232,6 +232,8 @@ class TrackObject : public NoCopy
// ------------------------------------------------------------------------
void setPaused(bool mode){ m_animator->setPaused(mode); }
// ------------------------------------------------------------------------
void setInitiallyVisible(bool val) { m_initially_visible = val; }
// ------------------------------------------------------------------------
/** Returns if a kart can drive on this object. */
bool isDriveable() const { return m_is_driveable; }
// ------------------------------------------------------------------------
@@ -20,9 +20,11 @@

#include "animations/ipo.hpp"
#include "animations/three_d_animation.hpp"
#include "config/stk_config.hpp"
#include "graphics/lod_node.hpp"
#include "graphics/material_manager.hpp"
#include "io/xml_node.hpp"
#include "network/network_config.hpp"
#include "physics/physical_object.hpp"
#include "tracks/track_object.hpp"
#include "utils/log.hpp"
@@ -66,14 +68,37 @@ void TrackObjectManager::add(const XMLNode &xml_node, scene::ISceneNode* parent,
*/
void TrackObjectManager::init()
{
for_var_in(TrackObject*, curr, m_all_objects)
int moveable_objects = 0;
bool warned = false;
for (unsigned i = 0; i < m_all_objects.m_contents_vector.size(); i++)
{
TrackObject* curr = m_all_objects.m_contents_vector[i];
curr->onWorldReady();

if (moveable_objects > stk_config->m_max_moveable_objects)
{
if (!warned)
{
Log::warn("TrackObjectManager",
"Too many moveable objects (>%d) in networking.",
stk_config->m_max_moveable_objects);
warned = true;
}
curr->setInitiallyVisible(false);
curr->setEnabled(false);
continue;
}

// onWorldReady will hide some track objects using scripting
if (curr->isEnabled() && curr->getPhysicalObject() &&
if (NetworkConfig::get()->isNetworking() &&
curr->isEnabled() && curr->getPhysicalObject() &&
curr->getPhysicalObject()->isDynamic())
{
curr->getPhysicalObject()->getBody()
->setActivationState(DISABLE_DEACTIVATION);
curr->getPhysicalObject()->addForRewind();
moveable_objects++;
}
}
} // init

@@ -35,7 +35,7 @@
#include <cwchar>
#include <fstream>
#include <iostream>
#include <vector>
#include <thread>

#if ENABLE_BIDI
# include <fribidi/fribidi.h>
@@ -443,6 +443,7 @@ const wchar_t* Translations::fribidize(const wchar_t* in_ptr)
#else
if (isRTLText(in_ptr))
{
std::lock_guard<std::mutex> lock(m_fribidized_mutex);
// Test if this string was already fribidized
std::map<const irr::core::stringw, const irr::core::stringw>::const_iterator
found = m_fribidized_strings.find(in_ptr);
@@ -543,25 +544,14 @@ const wchar_t* Translations::w_gettext(const char* original, const char* context
const std::string& original_t = (context == NULL ?
m_dictionary.translate(original) :
m_dictionary.translate_ctxt(context, original));

if (original_t == original)
{
static irr::core::stringw converted_string;
converted_string = StringUtils::utf8ToWide(original);

#if TRANSLATE_VERBOSE
std::wcout << L" translation : " << converted_string << std::endl;
#endif
return converted_string.c_str();
}

// print
//for (int n=0;; n+=4)
std::lock_guard<std::mutex> lock(m_gettext_mutex);

static core::stringw original_tw;
original_tw = StringUtils::utf8ToWide(original_t);
static std::map<std::thread::id, core::stringw> original_tw;
original_tw[std::this_thread::get_id()] = StringUtils::utf8ToWide(original_t);

const wchar_t* out_ptr = original_tw.c_str();
const wchar_t* out_ptr = original_tw.at(std::this_thread::get_id()).c_str();
if (REMOVE_BOM) out_ptr++;

#if TRANSLATE_VERBOSE
@@ -595,9 +585,8 @@ const wchar_t* Translations::w_ngettext(const wchar_t* singular, const wchar_t*
*/
const wchar_t* Translations::w_ngettext(const char* singular, const char* plural, int num, const char* context)
{
static core::stringw str_buffer;

#ifdef SERVER_ONLY
static core::stringw str_buffer;
str_buffer = StringUtils::utf8ToWide(singular);
return str_buffer.c_str();

@@ -607,8 +596,12 @@ const wchar_t* Translations::w_ngettext(const char* singular, const char* plural
m_dictionary.translate_plural(singular, plural, num) :
m_dictionary.translate_ctxt_plural(context, singular, plural, num));

str_buffer = StringUtils::utf8ToWide(res);
const wchar_t* out_ptr = str_buffer.c_str();
std::lock_guard<std::mutex> lock(m_ngettext_mutex);

static std::map<std::thread::id, core::stringw> str_buffer;
str_buffer[std::this_thread::get_id()] = StringUtils::utf8ToWide(res);

const wchar_t* out_ptr = str_buffer.at(std::this_thread::get_id()).c_str();
if (REMOVE_BOM) out_ptr++;

#if TRANSLATE_VERBOSE
@@ -21,6 +21,7 @@

#include <irrString.h>
#include <map>
#include <mutex>
#include <set>
#include <string>
#include <utility>
@@ -60,6 +61,7 @@ class Translations

std::string m_current_language_name;
std::string m_current_language_name_code;
std::mutex m_fribidized_mutex, m_gettext_mutex, m_ngettext_mutex;
#endif

public: