19
README.md
@ -64,13 +64,13 @@ mesa-common-dev pkg-config zlib1g-dev
|
||||
```
|
||||
### In-game recorder
|
||||
|
||||
In order to build the in-game recorder for STK, you have to install
|
||||
To build the in-game recorder for STK, you have to install
|
||||
libopenglrecorder from your distribution, or compile it yourself from [here](https://github.com/Benau/libopenglrecorder).
|
||||
Compilation instruction is explained there. If you don't need this feature, pass `-DBUILD_RECORDER=off` to cmake.
|
||||
|
||||
### Compiling
|
||||
|
||||
Run the following commands inside `stk-code` directory to compile SuperTuxKart:
|
||||
To compile SuperTuxKart, run the following commands inside `stk-code` directory:
|
||||
|
||||
```bash
|
||||
mkdir cmake_build
|
||||
@ -80,6 +80,21 @@ make -j4
|
||||
```
|
||||
STK can then be run from the build directory with `bin/supertuxkart`
|
||||
|
||||
#### Keeping your build up to date
|
||||
|
||||
To recompile the latest code without redownloading the entire source, first run the ```svn up``` command inside the 'stk-assets' directory, then run the following commands inside the 'stk-code' directory:
|
||||
|
||||
```bash
|
||||
git pull
|
||||
cd cmake_build
|
||||
cmake ..
|
||||
make -j4
|
||||
```
|
||||
|
||||
##### Build Speed Optimization
|
||||
|
||||
"-j4" is an example, for a faster build, use "-jx" instead, where "x" is the amount of CPU threads you have, minus one.
|
||||
|
||||
### Further options
|
||||
|
||||
To create a debug version of STK, run:
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0"?>
|
||||
<challenge version="2">
|
||||
<track id="stk_enterprise" laps="3"/>
|
||||
<mode major="single" minor="followtheleader"/>
|
||||
<mode major="single" minor="quickrace"/>
|
||||
<requirements trophies="110"/>
|
||||
|
||||
<hard>
|
||||
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 11 KiB |
@ -2,18 +2,21 @@
|
||||
<stkgui>
|
||||
<div x="2%" y="2%" width="96%" height="96%" layout="vertical-row" >
|
||||
|
||||
<spacer height="2%" width="25"/>
|
||||
<box width="100%" height="75%" padding="10" layout="vertical-row">
|
||||
<bright width="100%" text="Select a type of control that you prefer" align="center" text_align="left" />
|
||||
<box width="100%" height="80%" padding="10" layout="vertical-row">
|
||||
<bright width="100%" text="Select a type of control that you prefer" align="center" text_align="left" word_wrap="true"/>
|
||||
|
||||
<spacer height="15%" width="10"/>
|
||||
<spacer height="7%" width="10"/>
|
||||
|
||||
<ribbon id="control_type" height="60%" width="100%" align="center">
|
||||
<ribbon id="control_type" proportion="1" width="100%" align="center">
|
||||
<icon-button id="accelerometer" width="fit" height="fit" icon="gui/difficulty_medium.png"
|
||||
I18N="Control type" text="Accelerometer"/>
|
||||
<icon-button id="steering_wheel" width="fit" height="fit" icon="gui/difficulty_hard.png"
|
||||
I18N="Control type" text="Steering wheel"/>
|
||||
</ribbon>
|
||||
|
||||
<spacer height="12%" width="10"/>
|
||||
|
||||
<label width="100%" text="You can change it later in touch device settings." text_align="left" word_wrap="true"/>
|
||||
</box>
|
||||
|
||||
<spacer height="7%" width="10"/>
|
||||
|
Before Width: | Height: | Size: 117 KiB After Width: | Height: | Size: 72 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 126 KiB After Width: | Height: | Size: 73 KiB |
@ -312,21 +312,27 @@
|
||||
max-speed-increase="5" duration="1" fade-out-time="2" max="20" />
|
||||
|
||||
<!-- Slipstream
|
||||
base-speed: the speed for which length and width are valid.
|
||||
They are upscaled when faster and downscaled when slower.
|
||||
length: How far behind a kart slipstream works
|
||||
(note : this helps OTHER karts)
|
||||
width: how wide slipstream works furthest away from the kart.
|
||||
inner-factor: The proportion of the slipstreaming area with
|
||||
twice faster slipstream "credits" collection.
|
||||
collect-time: How many seconds of sstream give maximum benefit
|
||||
use-time: How long the benefit will last.
|
||||
add-power: Additional power due to sstreaming. 1 = +100%
|
||||
use-time: How long the benefit will last (obsolete, unused).
|
||||
add-power: Additional power due to sstreaming.
|
||||
min-speed: Minimum speed necessary for slipstream to take effect.
|
||||
max-speed-increase: How much the speed of the kart might exceed
|
||||
its normal maximum speed.
|
||||
duration: How long the higher speed lasts after slipstream stopped
|
||||
working.
|
||||
working (it works for at least collect-time more if the kart
|
||||
don't go behind another kart to get further sstreaming time)
|
||||
fade-out-time: How long the slip stream speed increase will
|
||||
gradually be reduced. -->
|
||||
<slipstream length="10" width="2" collect-time="2" use-time="5"
|
||||
add-power="3" min-speed="10" max-speed-increase="5"
|
||||
duration="1" fade-out-time="2" />
|
||||
<slipstream base-speed="20" length="8" width="4" inner-factor="0.5"
|
||||
collect-time="2" use-time="5" add-power="200" min-speed="8"
|
||||
max-speed-increase="5" duration="1" fade-out-time="2" />
|
||||
</characteristic>
|
||||
|
||||
<!-- The different difficulties (like easy, medium, hard) -->
|
||||
@ -360,9 +366,8 @@
|
||||
invulnerability-time="7" />
|
||||
<nitro engine-force="350" max-speed-increase="4.5" duration="1.5"
|
||||
fade-out-time="2.5" />
|
||||
<slipstream length="11" collect-time="1.5" use-time="2.5" add-power="3.2"
|
||||
min-speed="9" max-speed-increase="4" duration="1.2"
|
||||
fade-out-time="2.3" />
|
||||
<slipstream length="*0.9" collect-time="*0.9" add-power="*1.1"
|
||||
duration="*1.2" fade-out-time="*1.1" />
|
||||
</characteristic>
|
||||
<characteristic name="medium">
|
||||
<engine power="*0.63" max-speed="*1" brake-factor="*0.73"
|
||||
@ -374,8 +379,7 @@
|
||||
<explosion time="1.8" radius="5"
|
||||
invulnerability-time="6" />
|
||||
<nitro engine-force="425" consumption="1.4" duration="1" />
|
||||
<slipstream use-time="3.3" add-power="2.8" duration="0.9"
|
||||
fade-out-time="1.6" />
|
||||
<slipstream add-power="*0.9" duration="*0.9" fade-out-time="*0.9" />
|
||||
</characteristic>
|
||||
<characteristic name="heavy">
|
||||
<engine power="*1" max-speed="*1" brake-factor="*0.66"
|
||||
@ -390,8 +394,8 @@
|
||||
invulnerability-time="6" />
|
||||
<nitro engine-force="600" consumption="2" max-speed-increase="8"
|
||||
duration="0.7" fade-out-time="1.3" />
|
||||
<slipstream length="8.5" use-time="4" add-power="2.7" min-speed="10.5"
|
||||
max-speed-increase="8" duration="0.7" fade-out-time="1" />
|
||||
<slipstream length="*1.1" collect-time="*1.1" add-power="*0.8"
|
||||
duration="*0.7" fade-out-time="*0.7" />
|
||||
</characteristic>
|
||||
</kart-types>
|
||||
|
||||
|
90
data/shaders/sp_road_blending.frag
Normal file
@ -0,0 +1,90 @@
|
||||
in vec3 bitangent;
|
||||
in vec4 color;
|
||||
in float hue_change;
|
||||
in vec3 normal;
|
||||
in vec3 tangent;
|
||||
in vec2 uv;
|
||||
in vec4 world_position;
|
||||
in float camdist;
|
||||
|
||||
layout(location = 0) out vec4 o_diffuse_color;
|
||||
layout(location = 1) out vec4 o_normal_color;
|
||||
|
||||
#stk_include "utils/encode_normal.frag"
|
||||
#stk_include "utils/rgb_conversion.frag"
|
||||
#stk_include "utils/sp_texture_sampling.frag"
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 uuv = vec2(world_position.x, world_position.z);
|
||||
uuv *= 0.2;
|
||||
vec4 col = multi_sampleTextureLayer0(uv, camdist);
|
||||
|
||||
float mask = sampleTextureLayer4(uuv * 2.0).r;
|
||||
|
||||
//* (1.0 - color.g)
|
||||
mask = mix(1.0, mask, color.r);
|
||||
mask = mix(0.0, mask, 1.0 - color.g);
|
||||
if(mask < 0.5)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
|
||||
// Adding some skidding marks to the road
|
||||
float mask_2 = sampleTextureLayer4(uuv * 0.1).r;
|
||||
float mask_3 = sampleTextureLayer4(uuv * 3.5).r;
|
||||
mask_2 = pow(mask_2, 1.5);
|
||||
mask_2 *= pow(mask_3, 0.5);
|
||||
|
||||
float skidding_marks = sampleTextureLayer5(uv * 10).g;
|
||||
skidding_marks *= mask_2;
|
||||
col = mix(col, vec4(0.0, 0.0, 0.0, 1.0), skidding_marks);
|
||||
|
||||
float skidding_marks_2 = sampleTextureLayer5(uv * 15).g;
|
||||
skidding_marks_2 *= mask_2;
|
||||
col = mix(col, vec4(0.0, 0.0, 0.0, 1.0), skidding_marks_2);
|
||||
|
||||
// Add some cracks
|
||||
float cracks_marks = sampleTextureLayer5(uv * 11).b;
|
||||
float crack_mask = sampleTextureLayer4(uuv * 0.5).r;
|
||||
cracks_marks *= crack_mask;
|
||||
col = mix(col, vec4(0.0, 0.0, 0.0, 1.0), cracks_marks);
|
||||
|
||||
if (hue_change > 0.0)
|
||||
{
|
||||
float mask = col.a;
|
||||
vec3 old_hsv = rgbToHsv(col.rgb);
|
||||
float mask_step = step(mask, 0.5);
|
||||
#if !defined(Advanced_Lighting_Enabled)
|
||||
// For similar color
|
||||
float saturation = mask * 1.825; // 2.5 * 0.5 ^ (1. / 2.2)
|
||||
#else
|
||||
float saturation = mask * 2.5;
|
||||
#endif
|
||||
vec2 new_xy = mix(vec2(old_hsv.x, old_hsv.y), vec2(hue_change,
|
||||
max(old_hsv.y, saturation)), vec2(mask_step, mask_step));
|
||||
vec3 new_color = hsvToRgb(vec3(new_xy.x, new_xy.y, old_hsv.z));
|
||||
col = vec4(new_color.r, new_color.g, new_color.b, 1.0);
|
||||
}
|
||||
|
||||
vec3 final_color = col.xyz; // * color.xyz;
|
||||
|
||||
#if defined(Advanced_Lighting_Enabled)
|
||||
vec4 layer_2 = multi_sampleTextureLayer2(uv, camdist);
|
||||
vec4 layer_3 = multi_sampleTextureLayer3(uv, camdist);
|
||||
o_diffuse_color = vec4(final_color, layer_2.z);
|
||||
|
||||
vec3 tangent_space_normal = 2.0 * layer_3.xyz - 1.0;
|
||||
vec3 frag_tangent = normalize(tangent);
|
||||
vec3 frag_bitangent = normalize(bitangent);
|
||||
vec3 frag_normal = normalize(normal);
|
||||
mat3 t_b_n = mat3(frag_tangent, frag_bitangent, frag_normal);
|
||||
|
||||
vec3 world_normal = t_b_n * tangent_space_normal;
|
||||
|
||||
o_normal_color.xy = 0.5 * EncodeNormal(normalize(world_normal)) + 0.5;
|
||||
o_normal_color.zw = layer_2.xy;
|
||||
#else
|
||||
o_diffuse_color = vec4(final_color, 1.0);
|
||||
#endif
|
||||
}
|
17
data/shaders/sps_12_roadBlending.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<spshader>
|
||||
<shader-info name="roadBlending" fallback-shader="solid" use-tangents="Y"/>
|
||||
<first-pass vertex-shader="sp_pass.vert"
|
||||
fragment-shader="sp_road_blending.frag"
|
||||
skinned-mesh-shader="sp_skinning.vert">
|
||||
</first-pass>
|
||||
<!--
|
||||
<shadow-pass vertex-shader="sp_shadow.vert"
|
||||
fragment-shader="white.frag"
|
||||
skinned-mesh-shader="sp_skinning_shadow.vert">
|
||||
</shadow-pass>
|
||||
<uniform-assigners>
|
||||
<uniform-assigner name="layer"
|
||||
function="shadowCascadeUniformAssigner"/>
|
||||
</uniform-assigners>
|
||||
-->
|
||||
</spshader>
|
@ -36,17 +36,23 @@
|
||||
#include "utils/constants.hpp"
|
||||
#include "utils/mini_glm.hpp"
|
||||
|
||||
/** Creates the slip stream object using a moving texture.
|
||||
/** Creates the slip stream object
|
||||
* \param kart Pointer to the kart to which the slip stream
|
||||
* belongs to.
|
||||
*/
|
||||
SlipStream::SlipStream(AbstractKart* kart) : MovingTexture(0, 0), m_kart(kart)
|
||||
SlipStream::SlipStream(AbstractKart* kart)
|
||||
{
|
||||
m_node = NULL;
|
||||
m_kart = kart;
|
||||
m_moving = NULL;
|
||||
m_moving_fast = NULL;
|
||||
|
||||
#ifndef SERVER_ONLY
|
||||
if (CVS->isGLSL())
|
||||
{
|
||||
m_moving = new MovingTexture(0.0f, 0.0f);
|
||||
m_moving_fast = new MovingTexture(0.0f, 0.0f);
|
||||
|
||||
Material* material =
|
||||
material_manager->getMaterialSPM("slipstream.png", "");
|
||||
SP::SPMesh* mesh = createMesh(material);
|
||||
@ -59,23 +65,42 @@ SlipStream::SlipStream(AbstractKart* kart) : MovingTexture(0, 0), m_kart(kart)
|
||||
m_node->setVisible(false);
|
||||
SP::SPMeshNode* spmn = dynamic_cast<SP::SPMeshNode*>(m_node);
|
||||
assert(spmn);
|
||||
setSPTM(spmn->getTextureMatrix(0).data());
|
||||
m_moving->setSPTM(spmn->getTextureMatrix(0).data());
|
||||
|
||||
material = material_manager->getMaterialSPM("slipstream2.png", "");
|
||||
mesh = createMesh(material);
|
||||
m_node_fast = irr_driver->addMesh(mesh, "slipstream2");
|
||||
mesh->drop();
|
||||
debug_name = m_kart->getIdent()+" (slip-stream2)";
|
||||
m_node_fast->setName(debug_name.c_str());
|
||||
m_node_fast->setPosition(core::vector3df(0, 0 * 0.25f + 2.5f,
|
||||
m_kart->getKartLength()));
|
||||
m_node_fast->setVisible(false);
|
||||
spmn = dynamic_cast<SP::SPMeshNode*>(m_node_fast);
|
||||
assert(spmn);
|
||||
m_moving_fast->setSPTM(spmn->getTextureMatrix(0).data());
|
||||
}
|
||||
#endif
|
||||
|
||||
m_slipstream_time = 0.0f;
|
||||
|
||||
float length = m_kart->getKartProperties()->getSlipstreamLength();
|
||||
//The kart starts at 0 speed anyway
|
||||
float length = 0.0f;
|
||||
float kw = m_kart->getKartWidth();
|
||||
float ew = m_kart->getKartProperties()->getSlipstreamWidth();
|
||||
float ew = 0.0f;
|
||||
float kl = m_kart->getKartLength();
|
||||
|
||||
//making the slipstream quad start at the kart front
|
||||
//allows better results when the kart turns
|
||||
Vec3 p[4];
|
||||
p[0]=Vec3(-kw*0.5f, 0, -kl*0.5f );
|
||||
p[0]=Vec3(-kw*0.5f, 0, kl*0.5f );
|
||||
p[1]=Vec3(-ew*0.5f, 0, -kl*0.5f-length);
|
||||
p[2]=Vec3( ew*0.5f, 0, -kl*0.5f-length);
|
||||
p[3]=Vec3( kw*0.5f, 0, -kl*0.5f );
|
||||
p[3]=Vec3( kw*0.5f, 0, kl*0.5f );
|
||||
|
||||
m_slipstream_quad = new Quad(p[0], p[1], p[2], p[3]);
|
||||
//The position will be corrected in the update anyway
|
||||
m_slipstream_inner_quad = new Quad(p[0], p[1], p[2], p[3]);
|
||||
#ifndef SERVER_ONLY
|
||||
if (UserConfigParams::m_slipstream_debug)
|
||||
{
|
||||
@ -97,6 +122,22 @@ SlipStream::SlipStream(AbstractKart* kart) : MovingTexture(0, 0), m_kart(kart)
|
||||
m_debug_dc->recalculateBoundingBox();
|
||||
m_debug_dc->setParent(m_kart->getNode());
|
||||
SP::addDynamicDrawCall(m_debug_dc);
|
||||
|
||||
m_debug_dc2 = std::make_shared<SP::SPDynamicDrawCall>
|
||||
(scene::EPT_TRIANGLE_STRIP,
|
||||
SP::SPShaderManager::get()->getSPShader("additive"),
|
||||
material_manager->getDefaultSPMaterial("additive"));
|
||||
m_debug_dc2->getVerticesVector().resize(4);
|
||||
v = m_debug_dc2->getVerticesVector().data();
|
||||
for (unsigned i = 0; i < 4; i++)
|
||||
{
|
||||
v[i].m_position = p[idx[i]].toIrrVector();
|
||||
v[i].m_normal = 0x1FF << 10;
|
||||
v[i].m_color = red;
|
||||
}
|
||||
m_debug_dc2->recalculateBoundingBox();
|
||||
m_debug_dc2->setParent(m_kart->getNode());
|
||||
SP::addDynamicDrawCall(m_debug_dc2);
|
||||
}
|
||||
#endif
|
||||
} // SlipStream
|
||||
@ -110,11 +151,27 @@ SlipStream::~SlipStream()
|
||||
{
|
||||
irr_driver->removeNode(m_node);
|
||||
}
|
||||
if (m_node_fast)
|
||||
{
|
||||
irr_driver->removeNode(m_node_fast);
|
||||
}
|
||||
if (m_debug_dc)
|
||||
{
|
||||
m_debug_dc->removeFromSP();
|
||||
}
|
||||
if (m_debug_dc2)
|
||||
{
|
||||
m_debug_dc2->removeFromSP();
|
||||
}
|
||||
delete m_slipstream_quad;
|
||||
delete m_slipstream_inner_quad;
|
||||
#ifndef SERVER_ONLY
|
||||
if (CVS->isGLSL())
|
||||
{
|
||||
delete m_moving;
|
||||
delete m_moving_fast;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // ~SlipStream
|
||||
|
||||
@ -246,41 +303,56 @@ SP::SPMesh* SlipStream::createMesh(Material* material)
|
||||
/** Sets the animation intensity (or speed).
|
||||
* \param f Intensity: 0 = no slip stream,
|
||||
* 1 = collecting
|
||||
* 2 = using slip stream bonus
|
||||
* 2 = bonus can be used
|
||||
*/
|
||||
void SlipStream::setIntensity(float f, const AbstractKart *kart)
|
||||
{
|
||||
if (!kart || !m_node)
|
||||
if (!kart || !m_node || !m_node_fast)
|
||||
{
|
||||
if (m_node)
|
||||
{
|
||||
m_node->setVisible(false);
|
||||
}
|
||||
if (m_node_fast)
|
||||
{
|
||||
m_node_fast->setVisible(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
m_node->setVisible(true);
|
||||
float ktf = m_kart->getKartProperties()->getSlipstreamCollectTime();
|
||||
|
||||
const float above_terrain = 0.2f;
|
||||
core::vector3df my_pos = m_kart->getNode()->getPosition();
|
||||
my_pos.Y = m_kart->getHoT()+above_terrain;
|
||||
m_node->setPosition(my_pos);
|
||||
|
||||
core::vector3df other_pos = kart->getNode()->getPosition();
|
||||
other_pos.Y = kart->getHoT()+above_terrain;
|
||||
core::vector3df diff = other_pos - my_pos;
|
||||
core::vector3df rotation = diff.getHorizontalAngle();
|
||||
m_node->setRotation(rotation);
|
||||
float fs = diff.getLength()/m_length;
|
||||
|
||||
m_node->setPosition(my_pos);
|
||||
m_node->setRotation(rotation);
|
||||
m_node->setScale(core::vector3df(1, 1, fs));
|
||||
|
||||
// For real testing in game: this needs some tuning!
|
||||
m_node->setVisible(f!=0);
|
||||
MovingTexture::setSpeed(f, 0);
|
||||
m_node_fast->setPosition(my_pos);
|
||||
m_node_fast->setRotation(rotation);
|
||||
m_node_fast->setScale(core::vector3df(1, 1, fs));
|
||||
|
||||
m_node->setVisible(f>0.0f && f<ktf);
|
||||
m_node_fast->setVisible(f>=ktf);
|
||||
|
||||
//specify the texture speed movement
|
||||
if (f > 8.0f) f = 8.0f;
|
||||
f = f/2;
|
||||
|
||||
m_moving->setSpeed(f, 0);
|
||||
m_moving_fast->setSpeed(f, 0);
|
||||
|
||||
return;
|
||||
// For debugging: make the slip stream effect visible all the time
|
||||
m_node->setVisible(true);
|
||||
MovingTexture::setSpeed(1.0f, 0.0f);
|
||||
m_moving->setSpeed(1.0f, 0.0f);
|
||||
} // setIntensity
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -302,8 +374,7 @@ void SlipStream::updateSlipstreamPower()
|
||||
// See if we are currently using accumulated slipstream credits:
|
||||
// -------------------------------------------------------------
|
||||
if(m_slipstream_mode==SS_USE)
|
||||
{
|
||||
setIntensity(2.0f, NULL);
|
||||
{
|
||||
const KartProperties *kp = m_kart->getKartProperties();
|
||||
m_kart->increaseMaxSpeed(MaxSpeed::MS_INCREASE_SLIPSTREAM,
|
||||
kp->getSlipstreamMaxSpeedIncrease(),
|
||||
@ -320,23 +391,160 @@ void SlipStream::updateSlipstreamPower()
|
||||
* black: kart too slow
|
||||
* red: not inside of slipstream area
|
||||
* green: slipstream is being accumulated.
|
||||
* \param inner : bool to know if we apply the color to the inner quad or to the main one
|
||||
*/
|
||||
void SlipStream::setDebugColor(const video::SColor &color)
|
||||
void SlipStream::setDebugColor(const video::SColor &color, bool inner)
|
||||
{
|
||||
if (!m_debug_dc)
|
||||
if (!inner)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!m_debug_dc)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
video::S3DVertexSkinnedMesh* v = m_debug_dc->getVerticesVector().data();
|
||||
for (unsigned i = 0; i < 4; i++)
|
||||
video::S3DVertexSkinnedMesh* v = m_debug_dc->getVerticesVector().data();
|
||||
for (unsigned i = 0; i < 4; i++)
|
||||
{
|
||||
v[i].m_color = color;
|
||||
}
|
||||
m_debug_dc->setUpdateOffset(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
v[i].m_color = color;
|
||||
}
|
||||
m_debug_dc->setUpdateOffset(0);
|
||||
if (!m_debug_dc2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
video::S3DVertexSkinnedMesh* v = m_debug_dc2->getVerticesVector().data();
|
||||
for (unsigned i = 0; i < 4; i++)
|
||||
{
|
||||
v[i].m_color = color;
|
||||
}
|
||||
m_debug_dc2->setUpdateOffset(0);
|
||||
}
|
||||
} // setDebugColor
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** UpdateQuad
|
||||
*/
|
||||
void SlipStream::updateQuad()
|
||||
{
|
||||
|
||||
//Change the quad form to counteract the mismatch between
|
||||
//kart orientation and real direction
|
||||
|
||||
//Computations are contrieved by the fact we have several
|
||||
//different 3D vector, one for each library.
|
||||
Vec3 moving_xyz = m_kart->getPreviousXYZ() - m_kart->getXYZ();
|
||||
|
||||
//retrieve a vector rotated to kart direction
|
||||
btScalar bx,by,bz;//a btScalar is a float or a double
|
||||
bx = 1.0f;
|
||||
by = bz = 0.0f;
|
||||
btVector3 rotated_base;
|
||||
rotated_base.setValue(bx,by,bz);
|
||||
btQuaternion rotation = m_kart->getRotation();
|
||||
rotated_base = quatRotate(rotation,rotated_base);
|
||||
Vec3 direction_vector;
|
||||
//Z and X need to be inverted and X multiplied by -1 to match moving_xyz
|
||||
direction_vector = Vec3(rotated_base.getZ(), rotated_base.getY(), -rotated_base.getX());
|
||||
|
||||
//normalize the moving vector
|
||||
float vec_length = moving_xyz.x()*moving_xyz.x()
|
||||
+ moving_xyz.y()*moving_xyz.y()
|
||||
+ moving_xyz.z()*moving_xyz.z();
|
||||
if (vec_length != 0)
|
||||
{
|
||||
vec_length = core::reciprocal_squareroot(vec_length);
|
||||
float x,y,z;
|
||||
x = moving_xyz.x() * vec_length;
|
||||
y = moving_xyz.y() * vec_length;
|
||||
z = moving_xyz.z() * vec_length;
|
||||
moving_xyz = Vec3(x,y,z);
|
||||
}
|
||||
|
||||
//This vector gives us the change to apply in absolute coordinates
|
||||
Vec3 noffset = moving_xyz - direction_vector;
|
||||
|
||||
//But the quad position is in the kart coordinate space
|
||||
//So we rotate it back
|
||||
rotated_base.setValue(-noffset.z(),noffset.y(),noffset.x());
|
||||
rotation = rotation.inverse();
|
||||
rotated_base = quatRotate(rotation,rotated_base);
|
||||
noffset = Vec3(rotated_base.getZ(), rotated_base.getY(), -rotated_base.getX());
|
||||
|
||||
float speed_factor = m_kart->getSpeed()/m_kart->getKartProperties()->getSlipstreamBaseSpeed();
|
||||
float length = m_kart->getKartProperties()->getSlipstreamLength()*speed_factor;
|
||||
float kw = m_kart->getKartWidth();
|
||||
float ew = m_kart->getKartProperties()->getSlipstreamWidth()*speed_factor;
|
||||
float kl = m_kart->getKartLength();
|
||||
float offx = (kl*0.5f+length)*noffset.x();
|
||||
float offz = (kl*0.5f+length)*noffset.z();
|
||||
|
||||
//making the slipstream quad start at the kart front
|
||||
//allows better results when the kart turns
|
||||
Vec3 p[4];
|
||||
p[0]=Vec3(-kw*0.5f, 0, kl*0.5f );
|
||||
p[1]=Vec3(-ew*0.5f+offx, 0, -kl*0.5f-length+offz);
|
||||
p[2]=Vec3( ew*0.5f+offx, 0, -kl*0.5f-length+offz);
|
||||
p[3]=Vec3( kw*0.5f, 0, kl*0.5f );
|
||||
|
||||
//Update the slipstreaming quad
|
||||
m_slipstream_quad->setQuad(p[0], p[1], p[2], p[3]);
|
||||
|
||||
#ifndef SERVER_ONLY
|
||||
//recalculate quad position for debug drawing
|
||||
if (UserConfigParams::m_slipstream_debug)
|
||||
{
|
||||
video::S3DVertexSkinnedMesh* v =
|
||||
m_debug_dc->getVerticesVector().data();
|
||||
unsigned idx[] = { 0, 3, 1, 2 };
|
||||
for (unsigned i = 0; i < 4; i++)
|
||||
{
|
||||
v[i].m_position = p[idx[i]].toIrrVector();
|
||||
}
|
||||
m_debug_dc->recalculateBoundingBox();
|
||||
m_debug_dc->setParent(m_kart->getNode());
|
||||
SP::addDynamicDrawCall(m_debug_dc);
|
||||
}
|
||||
#endif
|
||||
float inner_factor = m_kart->getKartProperties()->getSlipstreamInnerFactor()*sqrt(speed_factor);
|
||||
length = length*inner_factor;
|
||||
ew = ew*inner_factor;
|
||||
if (ew > 0.5f) ew -= 0.5f;
|
||||
else ew = 0;
|
||||
|
||||
offx = (kl*0.5f+length)*noffset.x();
|
||||
offz = (kl*0.5f+length)*noffset.z();
|
||||
|
||||
p[0]=Vec3(-kw*0.5f, 0, kl*0.5f );
|
||||
p[1]=Vec3(-ew*0.5f+offx, 0, -kl*0.5f-length+offz);
|
||||
p[2]=Vec3( ew*0.5f+offx, 0, -kl*0.5f-length+offz);
|
||||
p[3]=Vec3( kw*0.5f, 0, kl*0.5f );
|
||||
|
||||
//Update the slipstreaming inner quad
|
||||
m_slipstream_inner_quad->setQuad(p[0], p[1], p[2], p[3]);
|
||||
|
||||
#ifndef SERVER_ONLY
|
||||
//recalculate inner quad position for debug drawing
|
||||
if (UserConfigParams::m_slipstream_debug)
|
||||
{
|
||||
video::S3DVertexSkinnedMesh* v =
|
||||
m_debug_dc2->getVerticesVector().data();
|
||||
unsigned idx[] = { 0, 3, 1, 2 };
|
||||
for (unsigned i = 0; i < 4; i++)
|
||||
{
|
||||
v[i].m_position = p[idx[i]].toIrrVector();
|
||||
}
|
||||
m_debug_dc2->recalculateBoundingBox();
|
||||
m_debug_dc2->setParent(m_kart->getNode());
|
||||
SP::addDynamicDrawCall(m_debug_dc2);
|
||||
}
|
||||
#endif
|
||||
|
||||
} //updateQuad
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Update, called once per timestep.
|
||||
* \param dt Time step size.
|
||||
@ -350,38 +558,60 @@ void SlipStream::update(float dt)
|
||||
|| m_kart->isGhostKart())
|
||||
return;
|
||||
|
||||
MovingTexture::update(dt);
|
||||
//there is no slipstreaming at low speed
|
||||
//and the quad may do weird things if going in reverse
|
||||
if(m_kart->getSpeed() > 1.0f)
|
||||
{
|
||||
updateQuad();
|
||||
}
|
||||
|
||||
#ifndef SERVER_ONLY
|
||||
if (CVS->isGLSL())
|
||||
{
|
||||
m_moving->update(dt);
|
||||
m_moving_fast->update(dt);
|
||||
}
|
||||
#endif
|
||||
|
||||
if(m_slipstream_mode==SS_USE)
|
||||
{
|
||||
m_slipstream_time -= dt;
|
||||
m_slipstream_time -= dt;//This makes slipstream_time decrease twice faster
|
||||
if(m_slipstream_time<0) m_slipstream_mode=SS_NONE;
|
||||
}
|
||||
|
||||
updateSlipstreamPower();
|
||||
|
||||
// If this kart is too slow for slipstreaming taking effect, do nothing
|
||||
// Use a margin because what really matters is the target's speed
|
||||
// If this kart is much slower than the minSpeed, then either its
|
||||
// targets are slower too, or it won't stay long enough behind them
|
||||
// --------------------------------------------------------------------
|
||||
// Define this to get slipstream effect shown even when the karts are
|
||||
// not moving. This is useful for debugging the graphics of SS-ing.
|
||||
//#define DISPLAY_SLIPSTREAM_WITH_0_SPEED_FOR_DEBUGGING
|
||||
#ifndef DISPLAY_SLIPSTREAM_WITH_0_SPEED_FOR_DEBUGGING
|
||||
if(m_kart->getSpeed() < kp->getSlipstreamMinSpeed())
|
||||
if(m_kart->getSpeed() < kp->getSlipstreamMinSpeed() - 2.0f)
|
||||
{
|
||||
setIntensity(0, NULL);
|
||||
#ifndef SERVER_ONLY
|
||||
if (CVS->isGLSL()) setIntensity(0, NULL);
|
||||
#endif
|
||||
m_slipstream_mode = SS_NONE;
|
||||
if(UserConfigParams::m_slipstream_debug)
|
||||
setDebugColor(video::SColor(255, 0, 0, 0));
|
||||
{
|
||||
setDebugColor(video::SColor(255, 0, 0, 0),false);
|
||||
setDebugColor(video::SColor(255, 0, 0, 0),true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Then test if this kart is in the slipstream range of another kart:
|
||||
// ------------------------------------------------------------------
|
||||
World *world = World::getWorld();
|
||||
unsigned int num_karts = world->getNumKarts();
|
||||
bool is_sstreaming = false;
|
||||
m_target_kart = NULL;
|
||||
World *world = World::getWorld();
|
||||
unsigned int num_karts = world->getNumKarts();
|
||||
bool is_sstreaming = false;
|
||||
bool is_inner_sstreaming = false;
|
||||
m_target_kart = NULL;
|
||||
|
||||
// Note that this loop can not be simply replaced with a shorter loop
|
||||
// using only the karts with a better position - since a kart might
|
||||
@ -389,6 +619,7 @@ void SlipStream::update(float dt)
|
||||
for(unsigned int i=0; i<num_karts; i++)
|
||||
{
|
||||
m_target_kart= world->getKart(i);
|
||||
|
||||
// Don't test for slipstream with itself, a kart that is being
|
||||
// rescued or exploding, a ghost kart or an eliminated kart
|
||||
if(m_target_kart==m_kart ||
|
||||
@ -396,6 +627,8 @@ void SlipStream::update(float dt)
|
||||
m_target_kart->isGhostKart() ||
|
||||
m_target_kart->isEliminated() ) continue;
|
||||
|
||||
const KartProperties *kp_target = m_target_kart->getKartProperties();
|
||||
|
||||
// Transform this kart location into target kart point of view
|
||||
Vec3 lc = m_target_kart->getTrans().inverse()(m_kart->getXYZ());
|
||||
|
||||
@ -404,37 +637,51 @@ void SlipStream::update(float dt)
|
||||
if (fabsf(lc.y()) > 6.0f) continue;
|
||||
|
||||
// If the kart we are testing against is too slow, no need to test
|
||||
// slipstreaming. Note: We compare the speed of the other kart
|
||||
// against the minimum slipstream speed kart of this kart - not
|
||||
// entirely sure if this makes sense, but it makes it easier to
|
||||
// give karts different slipstream properties.
|
||||
// slipstreaming.
|
||||
#ifndef DISPLAY_SLIPSTREAM_WITH_0_SPEED_FOR_DEBUGGING
|
||||
if (m_target_kart->getSpeed() < kp->getSlipstreamMinSpeed())
|
||||
if (m_target_kart->getSpeed() < kp_target->getSlipstreamMinSpeed())
|
||||
{
|
||||
if(UserConfigParams::m_slipstream_debug &&
|
||||
m_kart->getController()->isLocalPlayerController())
|
||||
{
|
||||
m_target_kart->getSlipstream()
|
||||
->setDebugColor(video::SColor(255, 0, 0, 0));
|
||||
->setDebugColor(video::SColor(255, 0, 0, 0), false);
|
||||
m_target_kart->getSlipstream()
|
||||
->setDebugColor(video::SColor(255, 0, 0, 0), true);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
// Quick test: the kart must be not more than
|
||||
// slipstream length+0.5*kart_length()+0.5*target_kart_length
|
||||
// slipstream length+0.5*kart_length()+target_kart_length
|
||||
// away from the other kart
|
||||
// (additional target_kart_length because that kart's center
|
||||
// is not the center of rotation of the slipstreaming quad)
|
||||
Vec3 delta = m_kart->getXYZ() - m_target_kart->getXYZ();
|
||||
float l = kp->getSlipstreamLength()
|
||||
+ 0.5f*( m_target_kart->getKartLength()
|
||||
+m_kart->getKartLength() );
|
||||
float l = kp_target->getSlipstreamLength();
|
||||
float speed_factor = m_target_kart->getSpeed()
|
||||
/kp_target->getSlipstreamBaseSpeed();
|
||||
l = l*speed_factor + m_target_kart->getKartLength()
|
||||
+ 0.5f*m_kart->getKartLength();
|
||||
if(delta.length2() > l*l)
|
||||
{
|
||||
if(UserConfigParams::m_slipstream_debug &&
|
||||
m_kart->getController()->isLocalPlayerController())
|
||||
m_target_kart->getSlipstream()
|
||||
->setDebugColor(video::SColor(255, 0, 0, 128));
|
||||
continue;
|
||||
}
|
||||
// Real test: if in slipstream quad of other kart
|
||||
// Real test 1: if in inner slipstream quad of other kart
|
||||
if(m_target_kart->getSlipstream()->m_slipstream_inner_quad
|
||||
->pointInside(lc))
|
||||
{
|
||||
is_inner_sstreaming = true;
|
||||
is_sstreaming = true;
|
||||
break;
|
||||
}
|
||||
if(UserConfigParams::m_slipstream_debug &&
|
||||
m_kart->getController()->isLocalPlayerController())
|
||||
m_target_kart->getSlipstream()
|
||||
->setDebugColor(video::SColor(255, 0, 0, 255),true);
|
||||
|
||||
// Real test2: if in slipstream quad of other kart
|
||||
if(m_target_kart->getSlipstream()->m_slipstream_quad
|
||||
->pointInside(lc))
|
||||
{
|
||||
@ -444,48 +691,74 @@ void SlipStream::update(float dt)
|
||||
if(UserConfigParams::m_slipstream_debug &&
|
||||
m_kart->getController()->isLocalPlayerController())
|
||||
m_target_kart->getSlipstream()
|
||||
->setDebugColor(video::SColor(255, 0, 0, 255));
|
||||
->setDebugColor(video::SColor(255, 0, 0, 255),false);
|
||||
} // for i < num_karts
|
||||
|
||||
if(!is_sstreaming)
|
||||
{
|
||||
if(UserConfigParams::m_slipstream_debug &&
|
||||
m_kart->getController()->isLocalPlayerController())
|
||||
{
|
||||
m_target_kart->getSlipstream()
|
||||
->setDebugColor(video::SColor(255, 255, 0, 0));
|
||||
->setDebugColor(video::SColor(255, 255, 0, 0),false);
|
||||
|
||||
m_target_kart->getSlipstream()
|
||||
->setDebugColor(video::SColor(255, 0, 255, 0),true);
|
||||
|
||||
}
|
||||
|
||||
if(isSlipstreamReady())
|
||||
{
|
||||
// The first time slipstream is ready after collecting
|
||||
// and you are leaving the slipstream area, you get a
|
||||
// zipper bonus.
|
||||
// and you are leaving the slipstream area, you get an
|
||||
// instant speed_increase
|
||||
if(m_slipstream_mode==SS_COLLECT)
|
||||
{
|
||||
m_slipstream_mode = SS_USE;
|
||||
m_kart->handleZipper();
|
||||
m_slipstream_time = kp->getSlipstreamCollectTime();
|
||||
m_kart->instantSpeedIncrease(MaxSpeed::MS_INCREASE_SLIPSTREAM,
|
||||
kp->getSlipstreamMaxSpeedIncrease(),
|
||||
kp->getSlipstreamMaxSpeedIncrease(),
|
||||
kp->getSlipstreamAddPower(),
|
||||
kp->getSlipstreamDuration(),
|
||||
kp->getSlipstreamFadeOutTime());
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_slipstream_time -=dt;
|
||||
if(m_slipstream_time<0) m_slipstream_mode = SS_NONE;
|
||||
setIntensity(0, NULL);
|
||||
#ifndef SERVER_ONLY
|
||||
if (CVS->isGLSL()) setIntensity(0, NULL);
|
||||
#endif
|
||||
return;
|
||||
} // if !is_sstreaming
|
||||
|
||||
if(UserConfigParams::m_slipstream_debug &&
|
||||
m_kart->getController()->isLocalPlayerController())
|
||||
m_target_kart->getSlipstream()->setDebugColor(video::SColor(255, 0, 255, 0));
|
||||
m_target_kart->getSlipstream()->setDebugColor(video::SColor(255, 128, 255, 0),false);
|
||||
|
||||
// Accumulate slipstream credits now
|
||||
m_slipstream_time = m_slipstream_mode==SS_NONE ? dt
|
||||
: m_slipstream_time+dt;
|
||||
//Twice as fast in the inner quad
|
||||
if (is_inner_sstreaming)
|
||||
{
|
||||
m_slipstream_time = m_slipstream_mode==SS_NONE ? 2*dt : m_slipstream_time+2*dt;
|
||||
|
||||
if(UserConfigParams::m_slipstream_debug &&
|
||||
m_kart->getController()->isLocalPlayerController())
|
||||
m_target_kart->getSlipstream()->setDebugColor(video::SColor(255, 0, 255, 128),true);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_slipstream_time = m_slipstream_mode==SS_NONE ? dt : m_slipstream_time+dt;
|
||||
}
|
||||
|
||||
//Cap the possible credits. Keep this similar to the animation speed cap.
|
||||
if (m_slipstream_time > 8.0f)
|
||||
m_slipstream_time = 8.0f;
|
||||
|
||||
if(isSlipstreamReady())
|
||||
m_kart->setSlipstreamEffect(9.0f);
|
||||
setIntensity(m_slipstream_time, m_target_kart);
|
||||
|
||||
#ifndef SERVER_ONLY
|
||||
if (CVS->isGLSL()) setIntensity(m_slipstream_time, m_target_kart);
|
||||
#endif
|
||||
m_slipstream_mode = SS_COLLECT;
|
||||
if (m_slipstream_time > kp->getSlipstreamCollectTime())
|
||||
{
|
||||
setIntensity(1.0f, m_target_kart);
|
||||
}
|
||||
} // update
|
||||
|
@ -44,18 +44,32 @@ class Material;
|
||||
/**
|
||||
* \ingroup graphics
|
||||
*/
|
||||
class SlipStream : public MovingTexture
|
||||
class SlipStream
|
||||
{
|
||||
private:
|
||||
/** The kart to which this smoke belongs. */
|
||||
AbstractKart *m_kart;
|
||||
|
||||
/** The moving texture for the normal node */
|
||||
|
||||
MovingTexture *m_moving;
|
||||
|
||||
/** The moving texture for the fast node */
|
||||
|
||||
MovingTexture *m_moving_fast;
|
||||
|
||||
/** The scene node. */
|
||||
scene::ISceneNode *m_node;
|
||||
|
||||
/** The fast scene node. */
|
||||
scene::ISceneNode *m_node_fast;
|
||||
|
||||
/** For debugging: a simple quad to display where slipstream works. */
|
||||
std::shared_ptr<SP::SPDynamicDrawCall> m_debug_dc;
|
||||
|
||||
/** For debugging: a simple quad to display where inner slipstream works. */
|
||||
std::shared_ptr<SP::SPDynamicDrawCall> m_debug_dc2;
|
||||
|
||||
/** The length of the slipstream cylinder. This is used to scale
|
||||
* the actual scene node correctly. */
|
||||
float m_length;
|
||||
@ -70,12 +84,16 @@ private:
|
||||
/** This is slipstream area if the kart is at 0,0,0 without rotation. */
|
||||
Quad *m_slipstream_quad;
|
||||
|
||||
/** This is the inner slipstream area if the kart is at 0,0,0 without rotation. */
|
||||
Quad *m_slipstream_inner_quad;
|
||||
|
||||
/** The kart from which this kart gets slipstream. Used by the AI to
|
||||
** overtake the right kart. */
|
||||
AbstractKart* m_target_kart;
|
||||
|
||||
SP::SPMesh* createMesh(Material* material);
|
||||
void setDebugColor(const video::SColor &color);
|
||||
void setDebugColor(const video::SColor &color, bool inner);
|
||||
void updateQuad();
|
||||
public:
|
||||
SlipStream (AbstractKart* kart);
|
||||
virtual ~SlipStream ();
|
||||
@ -97,4 +115,3 @@ public:
|
||||
bool inUse() const {return m_slipstream_mode==SS_USE; }
|
||||
}; // SlipStream
|
||||
#endif
|
||||
|
||||
|
@ -215,10 +215,14 @@ AbstractCharacteristic::ValueType AbstractCharacteristic::getType(
|
||||
return TYPE_FLOAT;
|
||||
case SLIPSTREAM_DURATION:
|
||||
return TYPE_FLOAT;
|
||||
case SLIPSTREAM_BASE_SPEED:
|
||||
return TYPE_FLOAT;
|
||||
case SLIPSTREAM_LENGTH:
|
||||
return TYPE_FLOAT;
|
||||
case SLIPSTREAM_WIDTH:
|
||||
return TYPE_FLOAT;
|
||||
case SLIPSTREAM_INNER_FACTOR:
|
||||
return TYPE_FLOAT;
|
||||
case SLIPSTREAM_COLLECT_TIME:
|
||||
return TYPE_FLOAT;
|
||||
case SLIPSTREAM_USE_TIME:
|
||||
@ -447,10 +451,14 @@ std::string AbstractCharacteristic::getName(CharacteristicType type)
|
||||
return "NITRO_MAX";
|
||||
case SLIPSTREAM_DURATION:
|
||||
return "SLIPSTREAM_DURATION";
|
||||
case SLIPSTREAM_BASE_SPEED:
|
||||
return "SLIPSTREAM_BASE_SPEED";
|
||||
case SLIPSTREAM_LENGTH:
|
||||
return "SLIPSTREAM_LENGTH";
|
||||
case SLIPSTREAM_WIDTH:
|
||||
return "SLIPSTREAM_WIDTH";
|
||||
case SLIPSTREAM_INNER_FACTOR:
|
||||
return "SLIPSTREAM_INNER_FACTOR";
|
||||
case SLIPSTREAM_COLLECT_TIME:
|
||||
return "SLIPSTREAM_COLLECT_TIME";
|
||||
case SLIPSTREAM_USE_TIME:
|
||||
@ -1471,6 +1479,18 @@ float AbstractCharacteristic::getSlipstreamDuration() const
|
||||
return result;
|
||||
} // getSlipstreamDuration
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
float AbstractCharacteristic::getSlipstreamBaseSpeed() const
|
||||
{
|
||||
float result;
|
||||
bool is_set = false;
|
||||
process(SLIPSTREAM_BASE_SPEED, &result, &is_set);
|
||||
if (!is_set)
|
||||
Log::fatal("AbstractCharacteristic", "Can't get characteristic %s",
|
||||
getName(SLIPSTREAM_BASE_SPEED).c_str());
|
||||
return result;
|
||||
} // getSlipstreamBaseSpeed
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
float AbstractCharacteristic::getSlipstreamLength() const
|
||||
{
|
||||
@ -1495,6 +1515,18 @@ float AbstractCharacteristic::getSlipstreamWidth() const
|
||||
return result;
|
||||
} // getSlipstreamWidth
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
float AbstractCharacteristic::getSlipstreamInnerFactor() const
|
||||
{
|
||||
float result;
|
||||
bool is_set = false;
|
||||
process(SLIPSTREAM_INNER_FACTOR, &result, &is_set);
|
||||
if (!is_set)
|
||||
Log::fatal("AbstractCharacteristic", "Can't get characteristic %s",
|
||||
getName(SLIPSTREAM_INNER_FACTOR).c_str());
|
||||
return result;
|
||||
} // getSlipstreamInnerFactor
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
float AbstractCharacteristic::getSlipstreamCollectTime() const
|
||||
{
|
||||
@ -1785,4 +1817,3 @@ bool AbstractCharacteristic::getSkidEnabled() const
|
||||
|
||||
|
||||
/* <characteristics-end acgetter> */
|
||||
|
||||
|
@ -194,8 +194,10 @@ public:
|
||||
|
||||
// Slipstream
|
||||
SLIPSTREAM_DURATION,
|
||||
SLIPSTREAM_BASE_SPEED,
|
||||
SLIPSTREAM_LENGTH,
|
||||
SLIPSTREAM_WIDTH,
|
||||
SLIPSTREAM_INNER_FACTOR,
|
||||
SLIPSTREAM_COLLECT_TIME,
|
||||
SLIPSTREAM_USE_TIME,
|
||||
SLIPSTREAM_ADD_POWER,
|
||||
@ -360,8 +362,10 @@ public:
|
||||
float getNitroMax() const;
|
||||
|
||||
float getSlipstreamDuration() const;
|
||||
float getSlipstreamBaseSpeed() const;
|
||||
float getSlipstreamLength() const;
|
||||
float getSlipstreamWidth() const;
|
||||
float getSlipstreamInnerFactor() const;
|
||||
float getSlipstreamCollectTime() const;
|
||||
float getSlipstreamUseTime() const;
|
||||
float getSlipstreamAddPower() const;
|
||||
@ -392,4 +396,3 @@ public:
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -310,6 +310,23 @@ public:
|
||||
virtual void increaseMaxSpeed(unsigned int category, float add_speed,
|
||||
float engine_force, float duration,
|
||||
float fade_out_time) = 0;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** This adjusts the top speed using increaseMaxSpeed, but additionally
|
||||
* causes an instant speed boost, which can be smaller than add-max-speed.
|
||||
* (e.g. a zipper can give an instant boost of 5 m/s, but over time would
|
||||
* allow the speed to go up by 10 m/s).
|
||||
* \param category The category for which the speed is increased.
|
||||
* \param add_max_speed Increase of the maximum allowed speed.
|
||||
* \param speed_boost An instant speed increase for this kart.
|
||||
* \param engine_force Additional engine force.
|
||||
* \param duration Duration of the increased speed.
|
||||
* \param fade_out_time How long the maximum speed will fade out linearly.
|
||||
*/
|
||||
virtual void instantSpeedIncrease(unsigned int category, float add_max_speed,
|
||||
float speed_boost, float engine_force, float duration,
|
||||
float fade_out_time) = 0;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Defines a slowdown, which is in fraction of top speed.
|
||||
* \param category The category for which the speed is increased.
|
||||
@ -459,6 +476,9 @@ public:
|
||||
* defined even if the kart is flying. */
|
||||
virtual const Vec3& getNormal() const = 0;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the position 0,25s before */
|
||||
virtual const Vec3& getPreviousXYZ() const = 0;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the height of the terrain. we're currently above */
|
||||
virtual float getHoT() const = 0;
|
||||
// ------------------------------------------------------------------------
|
||||
@ -494,4 +514,3 @@ public:
|
||||
#endif
|
||||
|
||||
/* EOF */
|
||||
|
||||
|
@ -147,6 +147,12 @@ Kart::Kart (const std::string& ident, unsigned int world_kart_id,
|
||||
m_boosted_ai = false;
|
||||
m_type = RaceManager::KT_AI;
|
||||
|
||||
for (int i=0;i<30;i++)
|
||||
{
|
||||
m_previous_xyz[i] = getXYZ();
|
||||
}
|
||||
m_time_previous_counter = 0.0f;
|
||||
|
||||
m_view_blocked_by_plunger = 0;
|
||||
m_has_caught_nolok_bubblegum = false;
|
||||
|
||||
@ -370,6 +376,12 @@ void Kart::reset()
|
||||
m_has_caught_nolok_bubblegum = false;
|
||||
m_is_jumping = false;
|
||||
|
||||
for (int i=0;i<30;i++)
|
||||
{
|
||||
m_previous_xyz[i] = getXYZ();
|
||||
}
|
||||
m_time_previous_counter = 0.0f;
|
||||
|
||||
// In case that the kart was in the air, in which case its
|
||||
// linear damping is 0
|
||||
if(m_body)
|
||||
@ -454,6 +466,15 @@ void Kart::increaseMaxSpeed(unsigned int category, float add_speed,
|
||||
fade_out_time);
|
||||
} // increaseMaxSpeed
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void Kart::instantSpeedIncrease(unsigned int category, float add_max_speed,
|
||||
float speed_boost, float engine_force, float duration,
|
||||
float fade_out_time)
|
||||
{
|
||||
m_max_speed->instantSpeedIncrease(category, add_max_speed, speed_boost,
|
||||
engine_force, duration, fade_out_time);
|
||||
} // instantSpeedIncrease
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void Kart::setSlowdown(unsigned int category, float max_speed_fraction,
|
||||
float fade_in_time)
|
||||
@ -1207,6 +1228,11 @@ void Kart::eliminate()
|
||||
m_stars_effect->reset();
|
||||
m_stars_effect->update(1);
|
||||
}
|
||||
|
||||
if (m_attachment)
|
||||
{
|
||||
m_attachment->clear();
|
||||
}
|
||||
|
||||
m_kart_gfx->setCreationRateAbsolute(KartGFX::KGFX_TERRAIN, 0);
|
||||
m_kart_gfx->setGFXInvisible();
|
||||
@ -1278,9 +1304,22 @@ void Kart::update(float dt)
|
||||
{
|
||||
m_kart_animation->update(dt);
|
||||
}
|
||||
|
||||
m_time_previous_counter += dt;
|
||||
while (m_time_previous_counter > (1.0f/120.0f))
|
||||
{
|
||||
m_previous_xyz[0] = getXYZ();
|
||||
for (int i=29;i>0;i--)
|
||||
{
|
||||
m_previous_xyz[i] = m_previous_xyz[i-1];
|
||||
}
|
||||
m_time_previous_counter -= (1.0f/120.0f);
|
||||
}
|
||||
|
||||
// Update the position and other data taken from the physics (or
|
||||
// an animation which calls setXYZ(), which also updates the kart
|
||||
// physical position).
|
||||
|
||||
Moveable::update(dt);
|
||||
|
||||
Vec3 front(0, 0, getKartLength()*0.5f);
|
||||
@ -1996,11 +2035,13 @@ 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
|
||||
// As the time deduction happens before, it can be an arbitrarily
|
||||
// small number > 0. Smaller means more responsive controls.
|
||||
if (m_controls.getNitro() && m_min_nitro_time <= 0.0f)
|
||||
m_min_nitro_time = 0.1f;
|
||||
m_min_nitro_time = 0.005f;
|
||||
}
|
||||
|
||||
bool increase_speed = (m_controls.getNitro() && isOnGround());
|
||||
bool increase_speed = (m_min_nitro_time > 0 && isOnGround());
|
||||
if (!increase_speed && m_min_nitro_time <= 0.0f)
|
||||
{
|
||||
if(m_nitro_sound->getStatus() == SFXBase::SFX_PLAYING)
|
||||
@ -2863,7 +2904,7 @@ void Kart::updateGraphics(float dt, const Vec3& offset_xyz,
|
||||
// --------------------------------------------------------
|
||||
float nitro_frac = 0;
|
||||
if ( (m_controls.getNitro() || m_min_nitro_time > 0.0f) &&
|
||||
isOnGround() && m_collected_energy > 0 )
|
||||
m_collected_energy > 0 )
|
||||
{
|
||||
// fabs(speed) is important, otherwise the negative number will
|
||||
// become a huge unsigned number in the particle scene node!
|
||||
@ -3050,6 +3091,14 @@ const Vec3& Kart::getNormal() const
|
||||
return m_terrain_info->getNormal();
|
||||
} // getNormal
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the position 0,25s before */
|
||||
const Vec3& Kart::getPreviousXYZ() const
|
||||
{
|
||||
return m_previous_xyz[29];
|
||||
} // getPreviousXYZ
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
void Kart::playSound(SFXBuffer* buffer)
|
||||
{
|
||||
|
@ -74,6 +74,11 @@ protected:
|
||||
* new lap is triggered. */
|
||||
Vec3 m_xyz_front;
|
||||
|
||||
/** The coordinates of the 30 previous positions */
|
||||
Vec3 m_previous_xyz[30];
|
||||
|
||||
float m_time_previous_counter;
|
||||
|
||||
/** Is time flying activated */
|
||||
bool m_is_jumping;
|
||||
|
||||
@ -273,6 +278,9 @@ public:
|
||||
virtual void increaseMaxSpeed(unsigned int category, float add_speed,
|
||||
float engine_force, float duration,
|
||||
float fade_out_time);
|
||||
virtual void instantSpeedIncrease(unsigned int category, float add_max_speed,
|
||||
float speed_boost, float engine_force, float duration,
|
||||
float fade_out_time);
|
||||
virtual void setSlowdown(unsigned int category, float max_speed_fraction,
|
||||
float fade_in_time);
|
||||
virtual float getSpeedIncreaseTimeLeft(unsigned int category) const;
|
||||
@ -470,6 +478,10 @@ public:
|
||||
/** Returns the normal of the terrain the kart is over atm. This is
|
||||
* defined even if the kart is flying. */
|
||||
virtual const Vec3& getNormal() const;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the position 0,25s before */
|
||||
virtual const Vec3& getPreviousXYZ() const;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** For debugging only: check if a kart is flying. */
|
||||
bool isFlying() const { return m_flying; }
|
||||
|
@ -1042,6 +1042,12 @@ float KartProperties::getSlipstreamDuration() const
|
||||
return m_cached_characteristic->getSlipstreamDuration();
|
||||
} // getSlipstreamDuration
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
float KartProperties::getSlipstreamBaseSpeed() const
|
||||
{
|
||||
return m_cached_characteristic->getSlipstreamBaseSpeed();
|
||||
} // getSlipstreamBaseSpeed
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
float KartProperties::getSlipstreamLength() const
|
||||
{
|
||||
@ -1054,6 +1060,12 @@ float KartProperties::getSlipstreamWidth() const
|
||||
return m_cached_characteristic->getSlipstreamWidth();
|
||||
} // getSlipstreamWidth
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
float KartProperties::getSlipstreamInnerFactor() const
|
||||
{
|
||||
return m_cached_characteristic->getSlipstreamInnerFactor();
|
||||
} // getSlipstreamInnerFactor
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
float KartProperties::getSlipstreamCollectTime() const
|
||||
{
|
||||
@ -1199,4 +1211,3 @@ bool KartProperties::getSkidEnabled() const
|
||||
} // getSkidEnabled
|
||||
|
||||
/* <characteristics-end kpgetter> */
|
||||
|
||||
|
@ -482,8 +482,10 @@ public:
|
||||
float getNitroMax() const;
|
||||
|
||||
float getSlipstreamDuration() const;
|
||||
float getSlipstreamBaseSpeed() const;
|
||||
float getSlipstreamLength() const;
|
||||
float getSlipstreamWidth() const;
|
||||
float getSlipstreamInnerFactor() const;
|
||||
float getSlipstreamCollectTime() const;
|
||||
float getSlipstreamUseTime() const;
|
||||
float getSlipstreamAddPower() const;
|
||||
|
@ -563,10 +563,14 @@ void XmlCharacteristic::load(const XMLNode *node)
|
||||
{
|
||||
sub_node->get("duration",
|
||||
&m_values[SLIPSTREAM_DURATION]);
|
||||
sub_node->get("base-speed",
|
||||
&m_values[SLIPSTREAM_BASE_SPEED]);
|
||||
sub_node->get("length",
|
||||
&m_values[SLIPSTREAM_LENGTH]);
|
||||
sub_node->get("width",
|
||||
&m_values[SLIPSTREAM_WIDTH]);
|
||||
sub_node->get("inner-factor",
|
||||
&m_values[SLIPSTREAM_INNER_FACTOR]);
|
||||
sub_node->get("collect-time",
|
||||
&m_values[SLIPSTREAM_COLLECT_TIME]);
|
||||
sub_node->get("use-time",
|
||||
@ -624,4 +628,3 @@ void XmlCharacteristic::load(const XMLNode *node)
|
||||
|
||||
/* <characteristics-end getXml> */
|
||||
} // load
|
||||
|
||||
|
10
src/main.cpp
@ -548,7 +548,8 @@ void cmdLineHelp()
|
||||
"./data/stk_config.xml\n"
|
||||
" -k, --numkarts=NUM Set number of karts on the racetrack.\n"
|
||||
" --kart=NAME Use kart NAME.\n"
|
||||
" --ai=a,b,... Use the karts a, b, ... for the AI.\n"
|
||||
" --ai=a,b,... Use the karts a, b, ... for the AI, and additional player kart.\n"
|
||||
" --aiNP=a,b,... Use the karts a, b, ... for the AI, no additional player kart.\n"
|
||||
" --laps=N Define number of laps to N.\n"
|
||||
" --mode=N N=1 Beginner, N=2 Intermediate, N=3 Expert, N=4 SuperTux.\n"
|
||||
" --type=N N=0 Normal, N=1 Time trial, N=2 Follow The Leader\n"
|
||||
@ -1113,6 +1114,13 @@ int handleCmdLine()
|
||||
race_manager->setNumKarts((int)l.size()+1);
|
||||
} // --ai
|
||||
|
||||
if(CommandLine::has("--aiNP", &s))
|
||||
{
|
||||
const std::vector<std::string> l=StringUtils::split(std::string(s),',');
|
||||
race_manager->setDefaultAIKartList(l);
|
||||
race_manager->setNumKarts((int)l.size());
|
||||
} // --aiNP
|
||||
|
||||
if(CommandLine::has( "--mode", &s) || CommandLine::has( "--difficulty", &s))
|
||||
{
|
||||
int n = atoi(s.c_str());
|
||||
|
@ -280,7 +280,9 @@ void RaceManager::computeRandomKartList()
|
||||
}
|
||||
|
||||
m_ai_kart_list.clear();
|
||||
unsigned int m = std::min( (unsigned) n, (unsigned)m_default_ai_list.size());
|
||||
|
||||
//Use the command line options AI list.
|
||||
unsigned int m = std::min( (unsigned) m_num_karts, (unsigned)m_default_ai_list.size());
|
||||
|
||||
for(unsigned int i=0; i<m; i++)
|
||||
{
|
||||
|
@ -69,7 +69,7 @@ GUIEngine::EventPropagation GeneralTextFieldDialog::processEvent(const std::stri
|
||||
else if (eventSource == "ok")
|
||||
{
|
||||
// If validation callback return true, dismiss the dialog
|
||||
if (m_val_cb(m_title, m_text_field))
|
||||
if (!m_self_destroy && m_val_cb(m_title, m_text_field))
|
||||
m_self_destroy = true;
|
||||
return GUIEngine::EVENT_BLOCK;
|
||||
}
|
||||
@ -88,7 +88,7 @@ void GeneralTextFieldDialog::onEnterPressedInternal()
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_val_cb(m_title, m_text_field))
|
||||
if (!m_self_destroy && m_val_cb(m_title, m_text_field))
|
||||
m_self_destroy = true;
|
||||
|
||||
} // onEnterPressedInternal
|
||||
|
@ -387,17 +387,25 @@ void RaceResultGUI::eventCallback(GUIEngine::Widget* widget,
|
||||
return;
|
||||
}
|
||||
|
||||
// This is a normal race, nothing was unlocked
|
||||
// -------------------------------------------
|
||||
StateManager::get()->popMenu();
|
||||
if (name == "top") // Setup new race
|
||||
{
|
||||
race_manager->exitRace();
|
||||
race_manager->setAIKartOverride("");
|
||||
Screen* newStack[] = { MainMenuScreen::getInstance(),
|
||||
RaceSetupScreen::getInstance(),
|
||||
NULL };
|
||||
StateManager::get()->resetAndSetStack(newStack);
|
||||
|
||||
//If pressing continue quickly in a losing challenge
|
||||
if (race_manager->raceWasStartedFromOverworld())
|
||||
{
|
||||
StateManager::get()->resetAndGoToScreen(MainMenuScreen::getInstance());
|
||||
OverWorld::enterOverWorld();
|
||||
}
|
||||
else
|
||||
{
|
||||
Screen* newStack[] = { MainMenuScreen::getInstance(),
|
||||
RaceSetupScreen::getInstance(),
|
||||
NULL };
|
||||
StateManager::get()->resetAndSetStack(newStack);
|
||||
}
|
||||
}
|
||||
else if (name == "middle") // Restart
|
||||
{
|
||||
|
@ -42,6 +42,20 @@ Quad::Quad(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, const Vec3 &p3,
|
||||
m_max_height_testing = Graph::MAX_HEIGHT_TESTING;
|
||||
} // Quad
|
||||
|
||||
/** Takes 4 points. */
|
||||
void Quad::setQuad(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, const Vec3 &p3)
|
||||
{
|
||||
m_p[0]=p0; m_p[1]=p1; m_p[2]=p2; m_p[3]=p3;
|
||||
|
||||
m_center = 0.25f*(p0+p1+p2+p3);
|
||||
m_min_height = std::min ( std::min(p0.getY(), p1.getY()),
|
||||
std::min(p2.getY(), p3.getY()) );
|
||||
m_max_height = std::max ( std::max(p0.getY(), p1.getY()),
|
||||
std::max(p2.getY(), p3.getY()) );
|
||||
m_min_height_testing = Graph::MIN_HEIGHT_TESTING;
|
||||
m_max_height_testing = Graph::MAX_HEIGHT_TESTING;
|
||||
} // setQuad
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Sets the vertices in a irrlicht vertex array to the 4 points of this quad.
|
||||
* \param v The vertex array in which to set the vertices.
|
||||
|
@ -84,6 +84,9 @@ public:
|
||||
/** Returns the center of a quad. */
|
||||
const Vec3& getCenter () const { return m_center; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Set new quad coordinates. */
|
||||
void setQuad (const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, const Vec3 &p3);
|
||||
// ------------------------------------------------------------------------
|
||||
void setHeightTesting(float min, float max)
|
||||
{
|
||||
m_min_height_testing = min;
|
||||
|
@ -3,7 +3,7 @@
|
||||
for track in abyss candela_city cocoa_temple cornfield_crossing fortmagma gran_paradiso_island greenvalley hacienda lighthouse mansion mines minigolf olivermath sandtrack scotland snowmountain snowtuxpeak stk_enterprise volcano_island xr591 zengarden; do
|
||||
echo "Testing $track"
|
||||
$1 --log=0 -R \
|
||||
--ai=nolok,nolok,nolok,nolok,nolok,nolok,nolok,nolok \
|
||||
--track=$track --difficulty=2 --type=1 --test-ai=2 \
|
||||
--aiNP=nolok,nolok,nolok,nolok,nolok,nolok,nolok,nolok,nolok,nolok,nolok,nolok,nolok,nolok,nolok \
|
||||
--track=$track --difficulty=3 --type=1 --test-ai=2 \
|
||||
--profile-laps=10 --no-graphics > stdout.$track
|
||||
done
|
||||
|
@ -48,7 +48,7 @@ Startup: time(std::vector<float>/floatVector), boost(std::vector<float>/floatVec
|
||||
Rescue: duration, vertOffset, height
|
||||
Explosion: duration, radius, invulnerabilityTime
|
||||
Nitro: duration, engineForce, consumption, smallContainer, bigContainer, maxSpeedIncrease, fadeOutTime, max
|
||||
Slipstream: duration, length, width, collectTime, useTime, addPower, minSpeed, maxSpeedIncrease, fadeOutTime
|
||||
Slipstream: duration, baseSpeed, length, width, innerFactor, collectTime, useTime, addPower, minSpeed, maxSpeedIncrease, fadeOutTime
|
||||
Skid: increase, decrease, max, timeTillMax, visual, visualTime, revertVisualTime, minSpeed, timeTillBonus(std::vector<float>/floatVector), bonusSpeed(std::vector<float>/floatVector), bonusTime(std::vector<float>/floatVector), bonusForce(std::vector<float>/floatVector), physicalJumpTime, graphicalJumpTime, postSkidRotateFactor, reduceTurnMin, reduceTurnMax, enabled(bool)"""
|
||||
|
||||
""" A GroupMember is an attribute of a group.
|
||||
@ -283,4 +283,3 @@ Operations:""")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
|