Merged with master and solved conflict with the new graph structure
This commit is contained in:
commit
c14ce23e66
1
.gitignore
vendored
1
.gitignore
vendored
@ -9,6 +9,7 @@ stk-editor/
|
||||
.config/
|
||||
supertuxkart-64
|
||||
make*.bat
|
||||
__pycache__
|
||||
|
||||
data/editor
|
||||
data/karts
|
||||
|
@ -1,6 +1,6 @@
|
||||
# root CMakeLists for the SuperTuxKart project
|
||||
project(SuperTuxKart)
|
||||
set(PROJECT_VERSION "0.8.1")
|
||||
set(PROJECT_VERSION "0.9.1")
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.4)
|
||||
if(NOT (CMAKE_MAJOR_VERSION VERSION_LESS 3))
|
||||
@ -15,7 +15,6 @@ if (NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "STKRelease")
|
||||
endif()
|
||||
|
||||
option(USE_WIIUSE "Support for wiimote input devices" ON)
|
||||
option(USE_FRIBIDI "Support for right-to-left languages" ON)
|
||||
option(CHECK_ASSETS "Check if assets are installed in ../stk-assets" ON)
|
||||
option(USE_SYSTEM_ANGELSCRIPT "Use system angelscript instead of built-in angelscript. If you enable this option, make sure to use a compatible version." OFF)
|
||||
@ -32,7 +31,9 @@ else()
|
||||
endif()
|
||||
|
||||
if(MINGW OR CYGWIN)
|
||||
set(USE_WIIUSE OFF)
|
||||
option(USE_WIIUSE "Support for wiimote input devices" OFF)
|
||||
else()
|
||||
option(USE_WIIUSE "Support for wiimote input devices" ON)
|
||||
endif()
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
|
BIN
data/CREDITS
BIN
data/CREDITS
Binary file not shown.
@ -4,6 +4,8 @@
|
||||
<card is="Intel(R) HD Graphics 3000" os="windows" disable="AdvancedPipeline"/>
|
||||
<card is="Intel(R) HD Graphics 3000" os="windows" disable="FramebufferSRGBWorking"/>
|
||||
<card contains="Intel" os="osx" disable="GI"/>
|
||||
<card contains="Intel" os="linux" version="<12.0" disable="ComputeShader"/>
|
||||
<card contains="Intel" os="linux" version="<12.0" disable="FramebufferSRGBCapable"/>
|
||||
<card contains="Intel" disable="TextureCompressionS3TC"/>
|
||||
<card contains="Intel" os="windows" disable="HighDefinitionTextures"/>
|
||||
<card contains="NVIDIA" os="windows" version="<344.65" disable="BufferStorage"/>
|
||||
|
@ -40,9 +40,12 @@
|
||||
<label id="highscore3" proportion="1" text="(Empty)"/>
|
||||
</div>
|
||||
|
||||
<spacer width="1" height="10%"/>
|
||||
<spacer width="1" height="2%"/>
|
||||
|
||||
<label id="author" width="100%" text_align="center" word_wrap="true"/>
|
||||
|
||||
<spacer width="1" height="10%"/>
|
||||
<label id="max-arena-players" width="100%" text_align="center" word_wrap="true"/>
|
||||
</div>
|
||||
|
||||
</box>
|
||||
|
404
data/kart_characteristics.xml
Normal file
404
data/kart_characteristics.xml
Normal file
@ -0,0 +1,404 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- Format
|
||||
It is possible to give relative values (factors and more) for each property.
|
||||
|
||||
The format as a regex is: ([+-*/](%d+|x))*
|
||||
An empty value means no change, a value without sign or with a '-' replaces
|
||||
the previous value. If an operator prefixes the string, e.g. *1.5 (- doesn't
|
||||
work because it's a sign). x will get replaced by the previous value which
|
||||
means *1.5 is equal to x*1.5. It's also possible to combine operations:
|
||||
+1.5*20 means "add 1.5 to the previous value and then multiply by 20".
|
||||
Note that it's computed sequentially from left to right and there is no
|
||||
operator precedence. Also whitespaces aren't allowed because they are used
|
||||
to split arrays.
|
||||
If you want to return the square of something use x*x or only *x.
|
||||
|
||||
ATTENTION: '-' is a special case if it is the first character of a number-
|
||||
string. It means that the number is negative and NOT that the following
|
||||
float will be substracted from the base value. So if x = 10 and the string
|
||||
"-5" is processed, the result will be -5 and not the same as "x-5", which
|
||||
would result in 10 - 5 = 5.
|
||||
-->
|
||||
<characteristics>
|
||||
<!-- The default values that can be modified by the difficulty, karts, etc.
|
||||
The values here should also be the values of the maximum difficulty. -->
|
||||
<characteristic name="base">
|
||||
<!-- ********** Physics ********** -->
|
||||
|
||||
<!-- Suspension
|
||||
stiffness: kart's suspension stiffness.
|
||||
rest: Length of suspension when at rest.
|
||||
travel-cm: maximum movement of suspension - in cm!!
|
||||
exp-string-response: dampen the suspension spring reaction
|
||||
exponentially. See
|
||||
http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?f=9&t=7369\&p=25236&hilit=vehicle#p25236
|
||||
for details.
|
||||
max-force: Maximum suspension force -->
|
||||
<suspension stiffness="140" rest="0.3" travel="0.29"
|
||||
exp-spring-response="false" max-force="12000" />
|
||||
|
||||
<!-- Values related to stability of the chassis: damping, and reduced
|
||||
impact of roll.
|
||||
downward-impulse-factor: A speed proportional impulse applied each
|
||||
frame that pushes the vehicle onto the ground.
|
||||
track-connection-accel: An artificial force that pulls a wheel to
|
||||
the ground if its off ground. Reduces the affect if a kart loses
|
||||
contact with the ground (i.e. it then can't steer or accelerate
|
||||
anymore).
|
||||
smooth-flying-impulse: apply a torque impulse to flying kart to keep
|
||||
them parallel to the ground. -->
|
||||
<stability roll-influence="0.3"
|
||||
chassis-linear-damping="0.2"
|
||||
chassis-angular-damping="0"
|
||||
downward-impulse-factor="5"
|
||||
track-connection-accel="2"
|
||||
smooth-flying-impulse="250" />
|
||||
|
||||
<!-- Turning
|
||||
radius: The turn radius of the kart at
|
||||
a given speed. The actual steering angle is dependent on the
|
||||
wheel base of the kart: radius = wheel_base/sin(steering_angle).
|
||||
The values below define that at speed 0 the turn radius is 2, at
|
||||
speed 10 the radius is 7.5 etc.
|
||||
The actual turn radius is piece-wise linearly interpolated. This
|
||||
allows for tighter turning at lower speeds, and also avoids that
|
||||
the kart becomes too hard to control at high speed (speeds of
|
||||
higher than 23 can only be reached with powerups).
|
||||
time-full-steer: This is the amount of change in steering depending
|
||||
on current steering. So if the steering is between 0 and 0.5,
|
||||
the time-for-steering-change is 0.15. If the current steering is
|
||||
between 0.5 and 1.0, the time-for-steering-change is 0.25.
|
||||
The speed is used as dt/time-for-steering-change.
|
||||
In short: steering at less than halfway is somewhat faster,
|
||||
which should avoid oversteering (by pressing the key for too long),
|
||||
but slower when you want to steer more. Overwall with the current
|
||||
settings the expected time-to-full-steer is:
|
||||
0.5 * 0.25 + 0.5 * 0.15 = 0.2 ... which is overall the same
|
||||
time we had previously. -->
|
||||
<turn radius="0:2.0 10:7.5 25:15 45:30"
|
||||
time-full-steer="0:0.17 0.5:0.17 0.5:0.28 1.0:0.28"
|
||||
time-reset-steer="0.1" />
|
||||
|
||||
<!-- Speed and acceleration
|
||||
power: The power of the kart
|
||||
max-speed: The base maximum speed of the kart in m/s
|
||||
brake-factor: Value used when braking.
|
||||
brake-time-increase: The brake force is multiplied by
|
||||
(1 + brake_time) * brake_time_increase - i.e. the longer the
|
||||
brake was pressed, the harder the kart will brake.
|
||||
max-speed-reverse-ratio is the percentage of max speed for reverse
|
||||
gear.
|
||||
-->
|
||||
<engine power="875" max-speed="25" brake-factor="15"
|
||||
brake-time-increase="6" max-speed-reverse-ratio="0.65" />
|
||||
|
||||
<!-- Simulated gears
|
||||
switch-ratio defines at what ratio of the maximum
|
||||
speed what gear is selected, e.g. 0.25 means that if the speed is
|
||||
bigger or equal to 0.25 * maxSpeed then use gear 1, 0.5 means if
|
||||
the speed is bigger or equal to 0.5 x maxSpeed then gear 2.
|
||||
gear-power-increase contains the increase in max power (to simulate
|
||||
different gears), e.g. 2.5 as first entry means: 2.5 * maxPower in gear 1
|
||||
| first | second | third | . -->
|
||||
<gear switch-ratio="0.25 0.7 1.0" power-increase="2.2 1.7 1.3" />
|
||||
|
||||
<!-- Mass of a kart -->
|
||||
<mass value="350" />
|
||||
|
||||
<!-- Wheels
|
||||
damping-relaxation/compression: for bullet
|
||||
damping parameters
|
||||
Radius and width of wheel
|
||||
front-right, front-left, rear-right and rear-left give the
|
||||
position of the physics raycast wheels relative to the center of
|
||||
gravity. Default is to use the corners of the chassis to attach
|
||||
the wheels to. -->
|
||||
<wheels damping-relaxation="35" damping-compression="5">
|
||||
<front-right position="0.38 0 0.6" />
|
||||
<front-left position="-0.38 0 0.6" />
|
||||
<rear-right position="0.38 0 -0.6" />
|
||||
<rear-left position="-0.38 0 -0.6" />
|
||||
</wheels>
|
||||
|
||||
|
||||
<!-- ********** Visuals ********** -->
|
||||
|
||||
<!-- Skidding
|
||||
increase: multiplicative increase of skidding factor in each frame.
|
||||
decrease: multiplicative decrease of skidding factor in each frame.
|
||||
max: maximum skidding factor = maximum increase of steering angle.
|
||||
time-till-max: Time till maximum skidding is reached.
|
||||
visual: Additional graphical rotation of kart. The graphical rotation
|
||||
of the kart also determines the direction the kart is driving to
|
||||
when skidding is stopped.
|
||||
visual-time: How long it takes for the visual skid to reach maximum.
|
||||
revert-visual-time: how long it takes when stopping a skid to revert
|
||||
the visual skid and bring visuals and physics in sync again.
|
||||
angular-velocity: Angular velocity to be used for the kart when skidding.
|
||||
min-speed: Minimum speed a kart must have before it can skid. Must be
|
||||
>0, otherwise the kart can skid at the start of the race.
|
||||
time-till-bonus: How long a kart needs to skid in order to get a bonus.
|
||||
bonus-force: A speedup applied to the kart whick skidded for a while.
|
||||
bonus-time: How long the bonus-force is applied.
|
||||
bonus-force: Additional engine force (this is used to offset the fact
|
||||
that turning after skidding (e.g. to correct direction) often uses
|
||||
up the skid bonus).
|
||||
post-skid-rotate-factor: a factor to be used to determine how much
|
||||
the chassis of a kart should rotate to match the graphical view.
|
||||
A factor of 1 is identical, a smaller factor will rotate the kart
|
||||
less (which might feel better).
|
||||
physical-jump-time: Time for a physical jump at the beginning of a skid.
|
||||
graphical-jump-time: Time for a graphics-only jump at the beginning
|
||||
of a skid.
|
||||
reduce-turn-min/max: The steering done by the controller (which is in
|
||||
[-1,1]) is mapped to [reduce-turn-min, reduce-turn-max] when skidding
|
||||
is active (for left turn, right turn will use [-max, -min]). The
|
||||
effect is that while you skid (say left) you can adjust the direction
|
||||
of the turn the kart is doing somewhat by steering to the left and right,
|
||||
but you will always keep on doing a left turn, just more or less. -->
|
||||
<skid increase="1.05" decrease="0.95" max="2.5" time-till-max="0.5"
|
||||
visual="1.25" visual-time="0.7" revert-visual-time="0.7"
|
||||
min-speed="10" time-till-bonus="1.0 3.0"
|
||||
bonus-speed="4.5 6.5" bonus-time="3.0 4.0"
|
||||
bonus-force="250 350"
|
||||
physical-jump-time="0" graphical-jump-time="0.4"
|
||||
post-skid-rotate-factor="1"
|
||||
reduce-turn-min="0.2" reduce-turn-max="0.8" enabled="true" />
|
||||
|
||||
<!-- Camera
|
||||
Distance between kart and camera.
|
||||
forward-up-angle: Angle between camera and plane of kart (pitch)
|
||||
when the camera is pointing forward
|
||||
backward-up-angle: Angle between camera and plane of kart (pitch)
|
||||
when the camera is pointing backwards. This is usually
|
||||
larger than the forward-up-angle, since the kart itself
|
||||
otherwise obstricts too much of the view. -->
|
||||
<camera distance="1.0" forward-up-angle="15"
|
||||
backward-up-angle="5" />
|
||||
|
||||
<!-- Jump animation
|
||||
animation-time: only if the estimated time for a jump is larger
|
||||
than this value will the jump animation being
|
||||
shown. -->
|
||||
<jump animation-time="0.5" />
|
||||
|
||||
<!-- Leaning related parameters, i.e. slightly leaning the karts when
|
||||
driving a fast curve.
|
||||
max: maximum leaning (i.e. when steering as much as possible at highest
|
||||
speed), in degrees.
|
||||
speed: Speed with which the leaning changes (in degree/second). -->
|
||||
<lean max="8.6" speed="5.0" />
|
||||
|
||||
|
||||
<!-- ********** Items ********** -->
|
||||
|
||||
<!-- Anvil
|
||||
weight: The additional weight an anvil adds to a kart.
|
||||
speed-factor: The additional slowdown caused by the anvil.
|
||||
duration: The time an anvil is active. -->
|
||||
<anvil duration="2.0" weight="150" speed-factor="0.2" />
|
||||
|
||||
<!-- Parachute
|
||||
friction: The friction increase when a parachute is attached.
|
||||
duration: The time an attached parachute is active
|
||||
duration-other: The time a parachute attached from other kart works
|
||||
lbound-fraction: The lower bound fraction of speed when lost will
|
||||
detach parachute. E.g. at nearly 0 speed, only 5% of speed
|
||||
need to be lost.
|
||||
ubound-fraction: The upper bound fraction of speed when lost will
|
||||
detach parachute. E.g. at max-speed 30% of speed must be lost.
|
||||
max-speed: A factor that decides the impact of rate of speed
|
||||
(distance between bounds) -->
|
||||
<parachute friction="2.0" duration="4.0" duration-other="8.0"
|
||||
lbound-fraction="0.95" ubound-fraction="0.7" max-speed="23" />
|
||||
|
||||
<!-- Bubblegum
|
||||
duration: How long the bubblegum lasts.
|
||||
speed-fraction: To what fraction of top-speed the speed is reduced.
|
||||
torque: To rotate the kart somewhat.
|
||||
fade-in-time: How quick the slowdown takes effect.
|
||||
shield-duration: How long the bubblegum shield lasts -->
|
||||
<bubblegum duration="1" speed-fraction="0.3" torque="500" fade-in-time="0.01"
|
||||
shield-duration="10.0" />
|
||||
|
||||
<!-- Zipper
|
||||
duration: Time a zipper is active.
|
||||
force: Additional zipper force.
|
||||
speed-gain: One time additional speed.
|
||||
max-speed-increase: Additional speed allowed on top of the
|
||||
kart-specific maximum kart speed.
|
||||
fade-out-time: determines how long it takes for a zipper
|
||||
to fade out (after 'time'). -->
|
||||
<zipper duration="3.5" force="250.0" speed-gain="4.5" max-speed-increase="15"
|
||||
fade-out-time="1.0" />
|
||||
|
||||
<!-- Swatter
|
||||
duration: How long can the swatter be active.
|
||||
distance: How close a kart or an item must be before it can be hit.
|
||||
This is the square of the real distance to accelerate the
|
||||
compution.
|
||||
squash-duration: How long a kart will remain squashed.
|
||||
squash-slowdown: Percentage of max speed that a kart is
|
||||
restricted to. -->
|
||||
<swatter duration="10" distance="9" squash-duration="5"
|
||||
squash-slowdown="0.5" />
|
||||
|
||||
<!-- Plunger and rubber band handling
|
||||
band-max-length: The maximum length of rubber band before it snaps.
|
||||
band-force: The force a plunger/rubber band applies to the kart(s).
|
||||
band-duration: The duration a rubber band acts.
|
||||
in-face-time determines how long it takes before a plunger
|
||||
in your face is removed. -->
|
||||
<plunger band-max-length="50" band-force="1500" band-duration="1"
|
||||
band-speed-increase="7" band-fade-out-time="3"
|
||||
in-face-time="4.5" />
|
||||
|
||||
|
||||
<!-- ********** Miscellaneous ********** -->
|
||||
|
||||
<!-- Startup
|
||||
If a kart starts within the specified time after 'go',
|
||||
it receives the corresponding bonus from 'boost'. Those
|
||||
fields must have the same size, and must be sorted by
|
||||
increasing times. -->
|
||||
<startup time="0.3 0.5"
|
||||
boost="6 3" />
|
||||
|
||||
<!-- Rescue
|
||||
duration: How long it takes the kart to be raised.
|
||||
height: how height the kart will be raised before it is
|
||||
dropped back onto the track.
|
||||
vert rescue offset: used to raise karts a bit higher before
|
||||
releasing them on the ground after a rescue. Used to avoid
|
||||
resetting karts into the track. Not sure if this is still
|
||||
necessary. -->
|
||||
<rescue vert-offset="0.0" duration="1.2" height="2" />
|
||||
|
||||
<!-- Explosion
|
||||
duration: how long it takes before the kart can drive again (this
|
||||
determines how height the kart is being thrown).
|
||||
invulnerability-time: how long a kart will be invulnerable
|
||||
after being hit by an explosion.
|
||||
radius: Kart closer to this value will be affected by
|
||||
an explosion as well. -->
|
||||
<explosion duration="2" radius="5"
|
||||
invulnerability-time="6" />
|
||||
|
||||
<!-- Nitro
|
||||
engine-force: additional engine power
|
||||
consumption: nitro consumption - heavier characters can be set
|
||||
to need more nitro than lighter character.
|
||||
small-container: how much energy a small container gives.
|
||||
big-container: how much energy a big container gives.
|
||||
max-speed-increase: How much the speed of a kart might exceed
|
||||
its maximum speed (in m/s).
|
||||
duration: How long the increased speed will be valid after
|
||||
the kart stops using nitro (and the fade-out-time starts).
|
||||
fade-out-time: Duration during which the increased maximum
|
||||
speed due to nitro fades out.
|
||||
max: How much nitro a kart can store. -->
|
||||
<nitro engine-force="600" consumption="1" small-container="1" big-container="3"
|
||||
max-speed-increase="5" duration="1" fade-out-time="2" max="20" />
|
||||
|
||||
<!-- Slipstream
|
||||
length: How far behind a kart slipstream works
|
||||
width: how wide slipstream works furthest away from the kart.
|
||||
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%
|
||||
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.
|
||||
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" />
|
||||
</characteristic>
|
||||
|
||||
<!-- The different difficulties (like easy, medium, hard) -->
|
||||
<difficulties>
|
||||
<characteristic name="easy">
|
||||
<engine power="*0.66" max-speed="*0.6" />
|
||||
<plunger in-face-time="3" />
|
||||
</characteristic>
|
||||
<characteristic name="medium">
|
||||
<engine power="*0.77" max-speed="*0.8" />
|
||||
<plunger in-face-time="4" />
|
||||
</characteristic>
|
||||
<characteristic name="hard">
|
||||
<engine power="*0.89" max-speed="*0.92" />
|
||||
</characteristic>
|
||||
<!-- This doesn't need to be changed because the most fast/heavy/extreme
|
||||
values should also be the default ones. -->
|
||||
<characteristic name="best" />
|
||||
</difficulties>
|
||||
|
||||
<!-- The different kart types, that can be specified in the kart.xml file -->
|
||||
<kart-types>
|
||||
<characteristic name="light">
|
||||
<engine power="*0.46" max-speed="*0.92" brake-factor="*1"
|
||||
max-speed-reverse-ratio="*0.77" />
|
||||
<gear switch-ratio="0.20 0.55 1" power-increase="5 4 3" />
|
||||
<mass value="*0.56" />
|
||||
<startup time="0.3 0.5"
|
||||
boost="8.5 4.5" />
|
||||
<explosion time="2.1" radius="5.5"
|
||||
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" />
|
||||
</characteristic>
|
||||
<characteristic name="medium">
|
||||
<engine power="*0.63" max-speed="*1" brake-factor="*0.73"
|
||||
max-speed-reverse-ratio="*0.62" />
|
||||
<gear switch-ratio="0.30 0.7 1.0" power-increase="2.2 2.2 2.5" />
|
||||
<mass value="*0.71" />
|
||||
<startup time="0.3 0.5"
|
||||
boost="4.2 2.6" />
|
||||
<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" />
|
||||
</characteristic>
|
||||
<characteristic name="heavy">
|
||||
<engine power="*1" max-speed="*1" brake-factor="*0.66"
|
||||
max-speed-reverse-ratio="*1" />
|
||||
<gear switch-ratio="0.45 0.70 1" power-increase="1.5 1.7 2.5" />
|
||||
<mass value="*1" />
|
||||
<swatter duration="10" distance="3" squash-duration="5"
|
||||
squash-slowdown="0.5" />
|
||||
<startup time="0.3 0.5"
|
||||
boost="3.8 2" />
|
||||
<explosion time="1.5" radius="4"
|
||||
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" />
|
||||
</characteristic>
|
||||
</kart-types>
|
||||
|
||||
<!-- Per-player settings/handicaps (or boosts) -->
|
||||
<player-characteristics>
|
||||
<characteristic name="normal" />
|
||||
<characteristic name="handicap">
|
||||
<engine brake-factor="*0.8" brake-time-increase="*0.85" max-speed-reverse-ratio="*0.8" />
|
||||
<bubblegum duration="*1.5" speed-fraction="*1.5" torque="*1.5" />
|
||||
<zipper duration="*0.8" force="*0.8" speed-gain="*0.8" max-speed-increase="*0.8" />
|
||||
<swatter duration="*0.8" squash-duration="*1.5" squash-slowdown="*1.8" />
|
||||
<plunger band-max-length="*0.8" band-speed-increase="*0.8" in-face-time="*1.3" />
|
||||
<startup time="*0.8 0.8" boost="*0.8 0.8" />
|
||||
<rescue duration="*1.5" />
|
||||
<explosion duration="*1.3" invulnerability-time="*0.7" />
|
||||
<nitro engine-force="*0.8" consumption="*1.1" max-speed-increase="*0.9" max="*0.8" />
|
||||
<slipstream length="*0.8" width="*0.8" collect-time="*1.5" use-time="*0.8"
|
||||
add-power="*0.8" min-speed="*0.8" max-speed-increase="*0.9" duration="*0.8" />
|
||||
</characteristic>
|
||||
</player-characteristics>
|
||||
</characteristics>
|
@ -85,24 +85,6 @@
|
||||
<!-- How long the music credits are shown. -->
|
||||
<credits music="10"/>
|
||||
|
||||
<!-- weight is the additional weight an anvil adds to a kart.
|
||||
speed-factor is the additional slowdown caused by the anvil.
|
||||
time is the time an anvil is active. -->
|
||||
<anvil time="2.0" weight="150" speed-factor="0.2"/>
|
||||
|
||||
<!-- friction is the friction increase when a parachute is attached.
|
||||
time is the time an attached parachute is active
|
||||
time-other is the time a parachute attached from other kart works
|
||||
lbound-fraction is the lower bound fraction of speed when lost will
|
||||
detach parachute. E.g. at nearly 0 speed, only 5% of speed
|
||||
need to be lost.
|
||||
ubound-fraction is the upper bound fraction of speed when lost will
|
||||
detach parachute. E.g. at max-speed 30% of speed must be lost.
|
||||
max-speed is a factor that decides the impact of rate of speed
|
||||
(distance between bounds) -->
|
||||
<parachute friction="2.0" time="4.0" time-other="8.0"
|
||||
lbound-fraction="0.95" ubound-fraction="0.7" max-speed="23"/>
|
||||
|
||||
<!-- time is the time till a bomb explodes. time-increase is the time added
|
||||
to timer when bomb is passed on. -->
|
||||
<bomb time="30.0" time-increase="-5.0"/>
|
||||
@ -150,22 +132,6 @@
|
||||
============================ -->
|
||||
<general-kart-defaults>
|
||||
|
||||
<!-- Camera: Distance between kart and camera.
|
||||
forward-up-angle: Angle between camera and plane of kart (pitch)
|
||||
when the camera is pointing forward
|
||||
backward-up-angle: Angle between camera and plane of kart (pitch)
|
||||
when the camera is pointing backwards. This is usually
|
||||
larger than the forward-up-angle, since the kart itself
|
||||
otherwise obstricts too much of the view. -->
|
||||
<camera distance="1.0" forward-up-angle="15"
|
||||
backward-up-angle="5"/>
|
||||
|
||||
<!-- Jump animation related values:
|
||||
animation-time: only if the estimated time for a jump is larger
|
||||
than this value will the jump animation being
|
||||
shown. -->
|
||||
<jump animation-time="0.5" />
|
||||
|
||||
<!-- Skidding: increase: multiplicative increase of skidding factor in each frame.
|
||||
decrease: multiplicative decrease of skidding factor in each frame.
|
||||
max: maximum skidding factor = maximum increase of steering angle.
|
||||
@ -339,69 +305,6 @@
|
||||
/>
|
||||
</ai>
|
||||
|
||||
<!-- The per-player difficulties in multiplayer games.
|
||||
These values are multiplied with the current values of a car
|
||||
so 1 means that nothing changes.
|
||||
The meaning of the different values is explained below this tag. -->
|
||||
<difficulties>
|
||||
<normal>
|
||||
<mass value="1.0"/>
|
||||
<engine brake-factor="1.0" brake-time-increase="1.0" max-speed-reverse-ratio="1.0" power="1.0" max-speed="1.0"/>
|
||||
<nitro consumption="1.0" max-speed-increase="1.0" duration="1.0" fade-out-time="1.0"/>
|
||||
<bubblegum time="1.0" speed-fraction="1.0" torque="1.0" fade-in-time="1.0"/>
|
||||
<rescue time="1.0"/>
|
||||
<explosion time="1.0" radius="1.0" invulnerability-time="1.0"/>
|
||||
<slipstream length="1.0" width="1.0" collect-time="1.0" use-time="1.0"
|
||||
add-power="1.0" min-speed="1.0" max-speed-increase="1.0" duration="1.0"
|
||||
fade-out-time="1.0"/>
|
||||
<plunger band-max-length="1.0" band-force="1.0" band-duration="1.0"
|
||||
band-speed-increase="1.0" band-fade-out-time="1.0" in-face-time="1.0"/>
|
||||
<zipper time="1.0" force="1.0" speed-gain="1.0" max-speed-increase="1.0"
|
||||
fade-out-time="1.0"/>
|
||||
<swatter duration="1.0" squash-duration="1.0" squash-slowdown="1.0"/>
|
||||
<startup time="1.0 1.0" boost="1.0 1.0"/>
|
||||
</normal>
|
||||
<handicap>
|
||||
<mass value="1.0"/>
|
||||
<engine brake-factor="0.8" brake-time-increase="0.85" max-speed-reverse-ratio="0.8" power="0.8" max-speed="0.8"/>
|
||||
<nitro consumption="1.1" max-speed-increase="0.9" duration="1.0" fade-out-time="1.0"/>
|
||||
<bubblegum time="1.5" speed-fraction="1.5" torque="1.5" fade-in-time="1.0"/>
|
||||
<rescue time="1.5"/>
|
||||
<explosion time="1.3" invulnerability-time="0.7"/>
|
||||
<slipstream length="0.8" width="0.8" collect-time="1.5" use-time="0.8"
|
||||
add-power="0.8" min-speed="0.8" max-speed-increase="0.9" duration="0.8"
|
||||
fade-out-time="1.0"/>
|
||||
<plunger band-max-length="0.8" band-force="1.0" band-duration="1.0"
|
||||
band-speed-increase="0.8" band-fade-out-time="1.0" in-face-time="1.3"/>
|
||||
<zipper time="0.8" force="0.8" speed-gain="0.8" max-speed-increase="0.8"
|
||||
fade-out-time="1.0"/>
|
||||
<swatter duration="0.8" squash-duration="1.5" squash-slowdown="1.8"/>
|
||||
<startup time="0.8 0.8" boost="0.8 0.8"/>
|
||||
</handicap>
|
||||
</difficulties>
|
||||
|
||||
<!-- Suspension related values. stiffness: kart's suspension stiffness.
|
||||
rest: Length of suspension when at rest.
|
||||
travel: maximum movement of suspension!!
|
||||
exp-string-response: dampen the suspension spring reaction
|
||||
exponentially.
|
||||
max-force: Maximum suspension force -->
|
||||
<suspension stiffness="140" rest="0.3" travel="0.29"
|
||||
exp-spring-response="false" max-force="12000"/>
|
||||
|
||||
<!-- Wheel related parameters: damping-relaxation/compression: for
|
||||
bullet, damping parameters.
|
||||
front-right, front-left, rear-right and rear-left give the
|
||||
position of the physics raycast wheels relative to the center of
|
||||
gravity. Default is to use the corners of the chassis to attach
|
||||
the wheels to. -->
|
||||
<wheels damping-relaxation="35" damping-compression="5">
|
||||
<front-right position="0.38 0 0.6" />
|
||||
<front-left position="-0.38 0 0.6" />
|
||||
<rear-right position="0.38 0 -0.6" />
|
||||
<rear-left position="-0.38 0 -0.6"/>
|
||||
</wheels>
|
||||
|
||||
<!-- Parameters for the speed-weighted objects:
|
||||
a bigger value for strength-factor leads to the speed of the kart more quickly affecting
|
||||
the strength of the animation (up to a maximum value that corresponds to the original animation) -->
|
||||
@ -411,23 +314,6 @@
|
||||
(like 10000000) disables bullet skidding. -->
|
||||
<friction slip="10000000"/>
|
||||
|
||||
<!-- Values related to stability of the chassis: damping, and reduced
|
||||
impact of roll.
|
||||
downward-impulse-factor: A speed proportional impulse applied each
|
||||
frame that pushes the vehicle onto the ground.
|
||||
track-connection-accel: An artificial force that pulls a wheel to
|
||||
the ground if its off ground. Reduces the affect if a kart loses
|
||||
contact with the ground (i.e. it then can't steer or accelerate
|
||||
anymore).
|
||||
smooth-flying-impulse: apply a torque impulse to flying kart to keep
|
||||
them parallel to the ground.-->
|
||||
<stability roll-influence="0.3"
|
||||
chassis-linear-damping="0.2"
|
||||
chassis-angular-damping="0"
|
||||
downward-impulse-factor="5"
|
||||
track-connection-accel="2"
|
||||
smooth-flying-impulse="250"/>
|
||||
|
||||
<!-- collision
|
||||
impulse-type: STK can apply an additional impulse in case of
|
||||
kart-track collision:
|
||||
@ -468,58 +354,6 @@
|
||||
impulse="3000" impulse-time="0.1" terrain-impulse="1600"
|
||||
restitution="1.0" bevel-factor="0.5 0.0 0.7"
|
||||
physical-wheel-position="-1" />
|
||||
|
||||
<!-- If a kart starts within the specified time after 'go',
|
||||
it receives the corresponding bonus from 'boost'. Those
|
||||
fields must have the same size, and must be sorted by
|
||||
increasing times. -->
|
||||
<startup time = "0.3 0.5"
|
||||
boost = "6 3" />
|
||||
|
||||
<!-- Rescue: time: How long it takes the kart to be raised.
|
||||
height: how height the kart will be raised before it is
|
||||
dropped back onto the track.
|
||||
vert rescue offset: used to raise karts a bit higher before
|
||||
releasing them on the ground after a rescue. Used to avoid
|
||||
resetting karts into the track. Not sure if this is still
|
||||
necessary. -->
|
||||
<rescue vert-offset="0.0" time="1.2" height="2"/>
|
||||
|
||||
<!-- Nitro: engine-force: additional engine power
|
||||
consumption: nitro consumption - heavier characters can be set
|
||||
to need more nitro than lighter character.
|
||||
small-container: how much energy a small container gives.
|
||||
big-container: how much energy a big container gives.
|
||||
max-speed-increase: How much the speed of a kart might exceed
|
||||
its maximum speed (in m/s).
|
||||
duration: How long the increased speed will be valid after
|
||||
the kart stops using nitro (and the fade-out-time starts).
|
||||
fade-out-time: Duration during which the increased maximum
|
||||
speed due to nitro fades out.
|
||||
max: How much nitro a kart can store.
|
||||
-->
|
||||
<nitro engine-force="500" consumption="1" small-container="1" big-container="3"
|
||||
max-speed-increase="5" duration="1" fade-out-time="2" max="20"/>
|
||||
|
||||
<!-- Bubble gum data:
|
||||
time: How long the bubblegum lasts.
|
||||
speed-fraction: To what fraction of top-speed the speed is reduced.
|
||||
torque: To rotate the kart somewhat.
|
||||
fade-in-time: How quick the slowdown takes effect.
|
||||
-->
|
||||
<bubblegum time="1" speed-fraction="0.3" torque="500" fade-in-time="0.01"/>
|
||||
|
||||
|
||||
<!-- time: Time a zipper is active.
|
||||
force: Additional zipper force.
|
||||
speed-gain: One time additional speed.
|
||||
max-speed-increase: Additional speed allowed on top of the
|
||||
kart-specific maximum kart speed.
|
||||
fade-out-time: determines how long it takes for a zipper
|
||||
to fade out (after 'time').
|
||||
-->
|
||||
<zipper time="3.5" force="250.0" speed-gain="4.5" max-speed-increase="15"
|
||||
fade-out-time="1.0" />
|
||||
|
||||
<!-- Skidding: increase: multiplicative increase of skidding factor in each frame.
|
||||
decrease: multiplicative decrease of skidding factor in each frame.
|
||||
@ -562,34 +396,6 @@
|
||||
post-skid-rotate-factor="1"
|
||||
reduce-turn-min="0.2" reduce-turn-max="0.8"/>
|
||||
|
||||
|
||||
<!-- Slipstream: length: How far behind a kart slipstream works
|
||||
width: how wide slipstream works furthest away from the kart.
|
||||
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%
|
||||
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.
|
||||
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"/>
|
||||
|
||||
|
||||
<!-- Kart-specific settings for the swatter:
|
||||
duration: how long can the swatter be active.
|
||||
distance: How close a kart or an item must be before it can be hit.
|
||||
squash-duration: How long a kart will remain squashed.
|
||||
squash-slowdown: percentage of max speed that a kart is
|
||||
restricted to. -->
|
||||
<swatter duration="10" distance="3" squash-duration="5"
|
||||
squash-slowdown="0.5"/>
|
||||
|
||||
<!-- Leaning related parameters, i.e. slightly leaning the karts when
|
||||
driving a fast curve.
|
||||
max: maximum leaning (i.e. when steering as much as possible at highest
|
||||
@ -597,156 +403,10 @@
|
||||
sped: Speed with which the leaning changes (in degree/second). -->
|
||||
<lean max="8.6" speed="5.0" />
|
||||
|
||||
<!-- turn-radius defines the turn radius of the kart at
|
||||
a given speed. The actual steering angle is dependent on the
|
||||
wheel base of the kart: radius = wheel_base/sin(steering_angle).
|
||||
The values below define that at speed 0 the turn radius is 2, at
|
||||
speed 10 the radius is 7.5 etc.
|
||||
The actual turn radius is piece-wise linearly interpolated. This
|
||||
allows for tighter turning at lower speeds, and also avoids that
|
||||
the kart becomes too hard to control at high speed (speeds of higher
|
||||
than 23 can only be reached with powerups).
|
||||
time-full-steer: This is the amount of change in steering depending
|
||||
on current steering. So if the steering is between 0 and 0.5,
|
||||
the time-for-steering-change is 0.15. If the current steering is
|
||||
between 0.5 and 1.0, the time-for-steering-change is 0.25.
|
||||
The speed is used as dt/time-for-steering-change.
|
||||
In short: steering at less than halfway is somewhat faster,
|
||||
which should avoid oversteering (by pressing the key for too long),
|
||||
but slower when you want to steer more. Overwall with the current
|
||||
settings the expected time-to-full-steer is:
|
||||
0.5 * 0.25 + 0.5 * 0.15 = 0.2 ... which is overall the same
|
||||
time we had previously.
|
||||
-->
|
||||
<turn turn-radius="0:2.0 10:7.5 25:15 45:30"
|
||||
time-full-steer ="0:0.15 0.5:0.15 0.5:0.25 1.0:0.25"
|
||||
time-reset-steer="0.1" />
|
||||
|
||||
<!-- Speed and acceleration related values: power and max-speed (in m/s)
|
||||
have 4 values, one for low, medium, hard, and supertux.
|
||||
brake-factor: Value used when braking.
|
||||
brake-time-increase: The brake force is multiplied by
|
||||
(1+brake_time*brake_time_increase - i.e. the longer the brake was
|
||||
pressed, the harder the kart will brake.
|
||||
max-speed-reverse-ratio is the percentage of max speed for reverse gear.
|
||||
-->
|
||||
<engine power="450 475 500 510" max-speed="17 21 23 25" brake-factor="11.0"
|
||||
brake-time-increase="6"
|
||||
max-speed-reverse-ratio="0.3"/>
|
||||
|
||||
<!-- Simulated gears: switch-ratio defines at what ratio of the maximum
|
||||
speed what gear is selected, e.g. 0.25 means that if the speed is
|
||||
bigger or equal to 0.25 x maxSpeed then use gear 1, 0.5 means if
|
||||
the speed is bigger or equal to 0.5 x maxSpeed then gear 2.
|
||||
gear-power-increase contains the increase in max power (to simulate
|
||||
different gears), e.g. 2.5 as first entry means: 2.5*maxPower in gear 1
|
||||
| first | second | third | . -->
|
||||
<gear switch-ratio="0.25 0.7 1.0" power-increase="2.2 1.7 1.3"/>
|
||||
|
||||
<!-- mass -->
|
||||
<mass value="225"/>
|
||||
|
||||
<!-- Kart-specific plunger and rubber band handling: max-length is
|
||||
the maximum length of rubber band before it snaps. force is
|
||||
the force a plunger/rubber band applies to the kart(s).
|
||||
duration is the duration a rubber band acts.
|
||||
in-face-time determines how long it takes before a plunger
|
||||
in your face is removed. -->
|
||||
<plunger band-max-length="50" band-force="1500" band-duration="1"
|
||||
band-speed-increase="7" band-fade-out-time="3"
|
||||
in-face-time="3 4 4.5 4.5"/>
|
||||
|
||||
<!-- Kart-specific explosion parameters.
|
||||
Time: how long it takes before the kart can drive again (this
|
||||
determines how height the kart is being thrown).
|
||||
Invulnerability-time: how long a kart will be invulnerable
|
||||
after being hit by an explosion.
|
||||
radius: Kart closer to this value will be affected by
|
||||
an explosion as well. -->
|
||||
<explosion time="2" radius="5"
|
||||
invulnerability-time="6" />
|
||||
|
||||
<kart-type>
|
||||
<light>
|
||||
<startup time = "0.3 0.5"
|
||||
boost = "8.5 4.5" />
|
||||
|
||||
<nitro engine-force="350" consumption="1" small-container="1" big-container="3"
|
||||
max-speed-increase="4.5" duration="1.5" fade-out-time="2.5" max="20"/>
|
||||
|
||||
<slipstream length="11" width="2" 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"/>
|
||||
|
||||
<turn turn-radius="0:3.0 10:10.0 25:20.0 45:40.0"
|
||||
time-full-steer ="0:0.15 0.5:0.15 0.5:0.25 1.0:0.25"
|
||||
time-reset-steer="0.1"/>
|
||||
|
||||
<engine power="250 300 350 400" max-speed="13 18 21 23.0" brake-factor="15.0"
|
||||
max-speed-reverse-ratio="0.5"/>
|
||||
|
||||
<gear switch-ratio="0.20 0.55 1" power-increase="5 4 3"/>
|
||||
|
||||
<mass value="195"/>
|
||||
|
||||
<explosion time="2.1" radius="5.5"
|
||||
invulnerability-time="7" />
|
||||
</light>
|
||||
|
||||
<medium>
|
||||
<startup time = "0.3 0.5"
|
||||
boost = "4.2 2.6" />
|
||||
|
||||
<nitro engine-force="425" consumption="1.4" small-container="1" big-container="3"
|
||||
max-speed-increase="5" duration="1.2" fade-out-time="2" max="20"/>
|
||||
|
||||
<slipstream length="10" width="2" collect-time="2" use-time="3.3"
|
||||
add-power="2.8" min-speed="10"
|
||||
max-speed-increase="5" duration="0.9" fade-out-time="1.6"/>
|
||||
|
||||
<turn turn-radius="0:4.5 10:16.0 25:30.0 45:60.0"
|
||||
time-full-steer ="0:0.17 0.5:0.17 0.5:0.28 1.0:0.28"
|
||||
time-reset-steer="0.1"/>
|
||||
|
||||
<engine power="375 450 525 550" max-speed="14 19 22.0 25" brake-factor="11.0"
|
||||
max-speed-reverse-ratio="0.4"/>
|
||||
|
||||
<gear switch-ratio="0.30 0.7 1.0" power-increase="2.2 2.2 2.5"/>
|
||||
|
||||
<mass value="250"/>
|
||||
|
||||
<explosion time="1.8" radius="5"
|
||||
invulnerability-time="6" />
|
||||
</medium>
|
||||
|
||||
<heavy>
|
||||
<startup time = "0.3 0.5"
|
||||
boost = "3.8 2" />
|
||||
|
||||
<nitro engine-force="600" consumption="2" small-container="1" big-container="3"
|
||||
max-speed-increase="8" duration="0.7" fade-out-time="1.3" max="20"/>
|
||||
|
||||
<slipstream length="8.5" width="2" collect-time="2" use-time="4"
|
||||
add-power="2.7" min-speed="10.5"
|
||||
max-speed-increase="8" duration="0.7" fade-out-time="1"/>
|
||||
|
||||
<swatter duration="10" distance="3" squash-duration="5"
|
||||
squash-slowdown="0.5"/>
|
||||
|
||||
<turn turn-radius="0:4.0 10:18.5 25:43.0 45:72.5"
|
||||
time-full-steer ="0:0.23 0.5:0.23 0.5:0.41 1.0:0.41"
|
||||
time-reset-steer="0.1"/>
|
||||
|
||||
<engine power="575 675 775 875" max-speed="15 20 23 25" brake-factor="10"
|
||||
max-speed-reverse-ratio="0.65"/>
|
||||
|
||||
<gear switch-ratio="0.45 0.70 1" power-increase="1.5 1.7 2.5"/>
|
||||
|
||||
<mass value="350"/>
|
||||
|
||||
<explosion time="1.5" radius="4"
|
||||
invulnerability-time="6" />
|
||||
</heavy>
|
||||
<light />
|
||||
<medium />
|
||||
<heavy />
|
||||
</kart-type>
|
||||
</general-kart-defaults>
|
||||
|
||||
|
@ -510,5 +510,6 @@ endif()
|
||||
add_library(stkirrlicht STATIC ${IRRLICHT_SOURCES})
|
||||
target_link_libraries(stkirrlicht ${PNG_LIBRARY} ${JPEG_LIBRARY} ${ZLIB_LIBRARY})
|
||||
|
||||
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(stkirrlicht imm32)
|
||||
endif()
|
||||
|
@ -49,6 +49,14 @@ namespace irr
|
||||
user receiver then no text will be sent to the console. */
|
||||
EET_LOG_TEXT_EVENT,
|
||||
|
||||
#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_)
|
||||
//! A input method event
|
||||
/** Input method events are created by the input method message and passed to IrrlichtDevice::postEventFromUser.
|
||||
Windows: Implemented.
|
||||
Linux / Other: Not yet implemented. */
|
||||
EET_IMPUT_METHOD_EVENT,
|
||||
#endif
|
||||
|
||||
//! A user event with user data.
|
||||
/** This is not used by Irrlicht and can be used to send user
|
||||
specific data though the system. The Irrlicht 'window handle'
|
||||
@ -142,6 +150,20 @@ namespace irr
|
||||
EMBSM_FORCE_32_BIT = 0x7fffffff
|
||||
};
|
||||
|
||||
#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_)
|
||||
//! Enumeration for all input method events
|
||||
enum EINPUT_METHOD_EVENT
|
||||
{
|
||||
//! a character from input method.
|
||||
EIME_CHAR_INPUT = 0,
|
||||
|
||||
//! change position of composition window
|
||||
EIME_CHANGE_POS,
|
||||
|
||||
EIME_FORCE_32_BIT = 0x7fffffff
|
||||
};
|
||||
#endif
|
||||
|
||||
namespace gui
|
||||
{
|
||||
|
||||
@ -411,6 +433,20 @@ struct SEvent
|
||||
s32 UserData2;
|
||||
};
|
||||
|
||||
#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_)
|
||||
struct SInputMethodEvent
|
||||
{
|
||||
//! Parent window handle for IMM functions (Windows only)
|
||||
void* Handle;
|
||||
|
||||
//! Character from Input Method
|
||||
wchar_t Char;
|
||||
|
||||
//! Type of input method event
|
||||
EINPUT_METHOD_EVENT Event;
|
||||
};
|
||||
#endif
|
||||
|
||||
EEVENT_TYPE EventType;
|
||||
union
|
||||
{
|
||||
@ -420,6 +456,9 @@ struct SEvent
|
||||
struct SJoystickEvent JoystickEvent;
|
||||
struct SLogEvent LogEvent;
|
||||
struct SUserEvent UserEvent;
|
||||
#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_)
|
||||
struct SInputMethodEvent InputMethodEvent;
|
||||
#endif
|
||||
};
|
||||
|
||||
};
|
||||
|
@ -26,11 +26,19 @@ public:
|
||||
}
|
||||
|
||||
//! Copies text to the clipboard
|
||||
#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_)
|
||||
virtual void copyToClipboard(const wchar_t* text) const = 0;
|
||||
#else
|
||||
virtual void copyToClipboard(const c8* text) const = 0;
|
||||
#endif
|
||||
|
||||
//! Get text from the clipboard
|
||||
/** \return Returns 0 if no string is in there. */
|
||||
#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_)
|
||||
virtual const wchar_t* getTextFromClipboard() const = 0;
|
||||
#else
|
||||
virtual const c8* getTextFromClipboard() const = 0;
|
||||
#endif
|
||||
|
||||
//! Get the processor speed in megahertz
|
||||
/** \param MHz The integer variable to store the speed in.
|
||||
|
@ -99,8 +99,10 @@
|
||||
|
||||
#if !defined(_IRR_WINDOWS_API_) && !defined(_IRR_OSX_PLATFORM_)
|
||||
#ifndef _IRR_SOLARIS_PLATFORM_
|
||||
#if !defined(__linux__) && !defined(__FreeBSD__)
|
||||
#define _IRR_LINUX_PLATFORM_
|
||||
#endif
|
||||
#endif
|
||||
#define _IRR_POSIX_API_
|
||||
#define _IRR_COMPILE_WITH_X11_DEVICE_
|
||||
#endif
|
||||
|
@ -267,6 +267,36 @@ public:
|
||||
|
||||
*this = &tmpbuf[idx];
|
||||
}
|
||||
|
||||
//! Constructs a string from an unsigned long long
|
||||
explicit string(unsigned long long number)
|
||||
: array(0), allocated(0), used(0)
|
||||
{
|
||||
// temporary buffer for 32 numbers
|
||||
|
||||
c8 tmpbuf[32]={0};
|
||||
u32 idx = 31;
|
||||
|
||||
// special case '0'
|
||||
|
||||
if (!number)
|
||||
{
|
||||
tmpbuf[30] = '0';
|
||||
*this = &tmpbuf[30];
|
||||
return;
|
||||
}
|
||||
|
||||
// add numbers
|
||||
|
||||
while(number && idx)
|
||||
{
|
||||
--idx;
|
||||
tmpbuf[idx] = (c8)('0' + (number % 10));
|
||||
number /= 10;
|
||||
}
|
||||
|
||||
*this = &tmpbuf[idx];
|
||||
}
|
||||
|
||||
|
||||
//! Constructor for copying a string from a pointer with a given length
|
||||
|
@ -2028,7 +2028,7 @@ public:
|
||||
{
|
||||
u32 tmp;
|
||||
sscanf(text, "0x%x", &tmp);
|
||||
Value = (void *) tmp;
|
||||
Value = reinterpret_cast<void *>(tmp);
|
||||
}
|
||||
|
||||
virtual E_ATTRIBUTE_TYPE getType() const
|
||||
|
@ -286,7 +286,11 @@ bool CGUIEditBox::processKey(const SEvent& event)
|
||||
const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd;
|
||||
const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin;
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_
|
||||
core::stringw s;
|
||||
#else
|
||||
core::stringc s;
|
||||
#endif
|
||||
s = Text.subString(realmbgn, realmend - realmbgn).c_str();
|
||||
Operator->copyToClipboard(s.c_str());
|
||||
}
|
||||
@ -299,7 +303,11 @@ bool CGUIEditBox::processKey(const SEvent& event)
|
||||
const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin;
|
||||
|
||||
// copy
|
||||
#ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_
|
||||
core::stringw sc;
|
||||
#else
|
||||
core::stringc sc;
|
||||
#endif
|
||||
sc = Text.subString(realmbgn, realmend - realmbgn).c_str();
|
||||
Operator->copyToClipboard(sc.c_str());
|
||||
|
||||
@ -329,7 +337,11 @@ bool CGUIEditBox::processKey(const SEvent& event)
|
||||
const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin;
|
||||
|
||||
// add new character
|
||||
#ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_
|
||||
const wchar_t* p = Operator->getTextFromClipboard();
|
||||
#else
|
||||
const c8* p = Operator->getTextFromClipboard();
|
||||
#endif
|
||||
if (p)
|
||||
{
|
||||
if (MarkBegin == MarkEnd)
|
||||
|
@ -599,6 +599,18 @@ bool CGUIEnvironment::postEventFromUser(const SEvent& event)
|
||||
|
||||
}
|
||||
break;
|
||||
#ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_
|
||||
case EET_IMPUT_METHOD_EVENT:
|
||||
{
|
||||
// todo : if CGUIEdit has not focus, close input method. Use WM_NOTIFY message.
|
||||
if (Focus)
|
||||
{
|
||||
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
|
||||
return Focus->OnEvent(event);
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
} // end switch
|
||||
|
@ -14,6 +14,7 @@ extern bool GLContextDebugBit;
|
||||
#include <unistd.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <time.h>
|
||||
#include <locale.h>
|
||||
#include "IEventReceiver.h"
|
||||
#include "ISceneManager.h"
|
||||
#include "IGUIEnvironment.h"
|
||||
@ -38,7 +39,7 @@ extern bool GLContextDebugBit;
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#include <sys/joystick.h>
|
||||
#else
|
||||
#elif defined(__linux__)
|
||||
|
||||
// linux/joystick.h includes linux/input.h, which #defines values for various KEY_FOO keys.
|
||||
// These override the irr::KEY_FOO equivalents, which stops key handling from working.
|
||||
@ -83,6 +84,7 @@ CIrrDeviceLinux::CIrrDeviceLinux(const SIrrlichtCreationParameters& param)
|
||||
: CIrrDeviceStub(param),
|
||||
#ifdef _IRR_COMPILE_WITH_X11_
|
||||
display(0), visual(0), screennr(0), window(0), StdHints(0), SoftwareImage(0),
|
||||
XInputMethod(0), XInputContext(0),
|
||||
#ifdef _IRR_COMPILE_WITH_OPENGL_
|
||||
glxWin(0),
|
||||
Context(0),
|
||||
@ -134,6 +136,10 @@ CIrrDeviceLinux::CIrrDeviceLinux(const SIrrlichtCreationParameters& param)
|
||||
if (!VideoDriver)
|
||||
return;
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_X11_
|
||||
createInputContext();
|
||||
#endif
|
||||
|
||||
createGUIAndScene();
|
||||
}
|
||||
|
||||
@ -168,6 +174,8 @@ CIrrDeviceLinux::~CIrrDeviceLinux()
|
||||
VideoDriver = NULL;
|
||||
}
|
||||
|
||||
destroyInputContext();
|
||||
|
||||
if (display)
|
||||
{
|
||||
#ifdef _IRR_COMPILE_WITH_OPENGL_
|
||||
@ -645,11 +653,11 @@ bool CIrrDeviceLinux::createWindow()
|
||||
GLX_SAMPLE_BUFFERS_SGIS, 1,
|
||||
GLX_SAMPLES_SGIS, CreationParams.AntiAlias, // 18,19
|
||||
#endif
|
||||
//#ifdef GL_ARB_framebuffer_sRGB
|
||||
// GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, CreationParams.HandleSRGB,
|
||||
//#elif defined(GL_EXT_framebuffer_sRGB)
|
||||
// GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT, CreationParams.HandleSRGB,
|
||||
//#endif
|
||||
#ifdef GLX_ARB_framebuffer_sRGB
|
||||
GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, CreationParams.HandleSRGB,
|
||||
#elif defined(GLX_EXT_framebuffer_sRGB)
|
||||
GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT, CreationParams.HandleSRGB,
|
||||
#endif
|
||||
GLX_STEREO, CreationParams.Stereobuffer?True:False,
|
||||
None
|
||||
};
|
||||
@ -796,11 +804,11 @@ bool CIrrDeviceLinux::createWindow()
|
||||
// GLX_USE_GL, which is silently ignored by glXChooseVisual
|
||||
CreationParams.Doublebuffer?GLX_DOUBLEBUFFER:GLX_USE_GL, // 14
|
||||
CreationParams.Stereobuffer?GLX_STEREO:GLX_USE_GL, // 15
|
||||
//#ifdef GL_ARB_framebuffer_sRGB
|
||||
// CreationParams.HandleSRGB?GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB:GLX_USE_GL,
|
||||
//#elif defined(GL_EXT_framebuffer_sRGB)
|
||||
// CreationParams.HandleSRGB?GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT:GLX_USE_GL,
|
||||
//#endif
|
||||
#ifdef GLX_ARB_framebuffer_sRGB
|
||||
CreationParams.HandleSRGB?GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB:GLX_USE_GL,
|
||||
#elif defined(GLX_EXT_framebuffer_sRGB)
|
||||
CreationParams.HandleSRGB?GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT:GLX_USE_GL,
|
||||
#endif
|
||||
None
|
||||
};
|
||||
|
||||
@ -1154,6 +1162,123 @@ void CIrrDeviceLinux::createDriver()
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_X11_
|
||||
bool CIrrDeviceLinux::createInputContext()
|
||||
{
|
||||
// One one side it would be nicer to let users do that - on the other hand
|
||||
// not setting the environment locale will not work when using i18n X11 functions.
|
||||
// So users would have to call it always or their input is broken badly.
|
||||
// We can restore immediately - so won't mess with anything in users apps.
|
||||
core::stringc oldLocale(setlocale(LC_CTYPE, NULL));
|
||||
setlocale(LC_CTYPE, ""); // use environment locale
|
||||
|
||||
if ( !XSupportsLocale() )
|
||||
{
|
||||
os::Printer::log("Locale not supported. Falling back to non-i18n input.", ELL_WARNING);
|
||||
setlocale(LC_CTYPE, oldLocale.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
XInputMethod = XOpenIM(display, NULL, NULL, NULL);
|
||||
if ( !XInputMethod )
|
||||
{
|
||||
setlocale(LC_CTYPE, oldLocale.c_str());
|
||||
os::Printer::log("XOpenIM failed to create an input method. Falling back to non-i18n input.", ELL_WARNING);
|
||||
return false;
|
||||
}
|
||||
|
||||
XIMStyles *im_supported_styles;
|
||||
XGetIMValues(XInputMethod, XNQueryInputStyle, &im_supported_styles, (char*)NULL);
|
||||
XIMStyle bestStyle = 0;
|
||||
// TODO: If we want to support languages like chinese or japanese as well we probably have to work with callbacks here.
|
||||
XIMStyle supportedStyle = XIMPreeditNone | XIMStatusNone;
|
||||
for (int i=0; i < im_supported_styles->count_styles; ++i)
|
||||
{
|
||||
XIMStyle style = im_supported_styles->supported_styles[i];
|
||||
if ((style & supportedStyle) == style) /* if we can handle it */
|
||||
{
|
||||
bestStyle = style;
|
||||
break;
|
||||
}
|
||||
}
|
||||
XFree(im_supported_styles);
|
||||
|
||||
if ( !bestStyle )
|
||||
{
|
||||
XDestroyIC(XInputContext);
|
||||
XInputContext = 0;
|
||||
|
||||
os::Printer::log("XInputMethod has no input style we can use. Falling back to non-i18n input.", ELL_WARNING);
|
||||
setlocale(LC_CTYPE, oldLocale.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
XInputContext = XCreateIC(XInputMethod,
|
||||
XNInputStyle, bestStyle,
|
||||
XNClientWindow, window,
|
||||
(char*)NULL);
|
||||
if (!XInputContext )
|
||||
{
|
||||
os::Printer::log("XInputContext failed to create an input context. Falling back to non-i18n input.", ELL_WARNING);
|
||||
setlocale(LC_CTYPE, oldLocale.c_str());
|
||||
return false;
|
||||
}
|
||||
XSetICFocus(XInputContext);
|
||||
setlocale(LC_CTYPE, oldLocale.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
void CIrrDeviceLinux::destroyInputContext()
|
||||
{
|
||||
if ( XInputContext )
|
||||
{
|
||||
XUnsetICFocus(XInputContext);
|
||||
XDestroyIC(XInputContext);
|
||||
XInputContext = 0;
|
||||
}
|
||||
if ( XInputMethod )
|
||||
{
|
||||
XCloseIM(XInputMethod);
|
||||
XInputMethod = 0;
|
||||
}
|
||||
}
|
||||
|
||||
EKEY_CODE CIrrDeviceLinux::getKeyCode(XEvent &event)
|
||||
{
|
||||
EKEY_CODE keyCode = (EKEY_CODE)0;
|
||||
|
||||
SKeyMap mp;
|
||||
mp.X11Key = XkbKeycodeToKeysym(display, event.xkey.keycode, 0, 0);
|
||||
// mp.X11Key = XKeycodeToKeysym(XDisplay, event.xkey.keycode, 0); // deprecated, if we still find platforms which need that we have to use some define
|
||||
const s32 idx = KeyMap.binary_search(mp);
|
||||
if (idx != -1)
|
||||
{
|
||||
keyCode = (EKEY_CODE)KeyMap[idx].Win32Key;
|
||||
}
|
||||
if (keyCode == 0)
|
||||
{
|
||||
// Any value is better than none, that allows at least using the keys.
|
||||
// Worst case is that some keys will be identical, still better than _all_
|
||||
// unknown keys being identical.
|
||||
if ( !mp.X11Key )
|
||||
{
|
||||
keyCode = (EKEY_CODE)event.xkey.keycode;
|
||||
os::Printer::log("No such X11Key, using event keycode", core::stringc(event.xkey.keycode).c_str(), ELL_INFORMATION);
|
||||
}
|
||||
else if (idx == -1)
|
||||
{
|
||||
keyCode = (EKEY_CODE)mp.X11Key;
|
||||
os::Printer::log("EKEY_CODE not found, using orig. X11 keycode", core::stringc(mp.X11Key).c_str(), ELL_INFORMATION);
|
||||
}
|
||||
else
|
||||
{
|
||||
keyCode = (EKEY_CODE)mp.X11Key;
|
||||
os::Printer::log("EKEY_CODE is 0, using orig. X11 keycode", core::stringc(mp.X11Key).c_str(), ELL_INFORMATION);
|
||||
}
|
||||
}
|
||||
return keyCode;
|
||||
}
|
||||
#endif
|
||||
|
||||
//! runs the device. Returns false if device wants to be deleted
|
||||
bool CIrrDeviceLinux::run()
|
||||
@ -1330,52 +1455,60 @@ bool CIrrDeviceLinux::run()
|
||||
(next_event.xkey.keycode == event.xkey.keycode) &&
|
||||
(next_event.xkey.time - event.xkey.time) < 2) // usually same time, but on some systems a difference of 1 is possible
|
||||
{
|
||||
/* Ignore the key release event */
|
||||
// Ignore the key release event
|
||||
break;
|
||||
}
|
||||
}
|
||||
// fall-through in case the release should be handled
|
||||
|
||||
irrevent.EventType = irr::EET_KEY_INPUT_EVENT;
|
||||
irrevent.KeyInput.PressedDown = false;
|
||||
irrevent.KeyInput.Char = 0; // on release that's undefined
|
||||
irrevent.KeyInput.Control = (event.xkey.state & ControlMask) != 0;
|
||||
irrevent.KeyInput.Shift = (event.xkey.state & ShiftMask) != 0;
|
||||
irrevent.KeyInput.Key = getKeyCode(event);
|
||||
|
||||
postEventFromUser(irrevent);
|
||||
break;
|
||||
|
||||
case KeyPress:
|
||||
{
|
||||
SKeyMap mp;
|
||||
char buf[8]={0};
|
||||
XLookupString(&event.xkey, buf, sizeof(buf), &mp.X11Key, NULL);
|
||||
|
||||
irrevent.EventType = irr::EET_KEY_INPUT_EVENT;
|
||||
irrevent.KeyInput.PressedDown = (event.type == KeyPress);
|
||||
// mbtowc(&irrevent.KeyInput.Char, buf, sizeof(buf));
|
||||
irrevent.KeyInput.Char = ((wchar_t*)(buf))[0];
|
||||
irrevent.KeyInput.Control = (event.xkey.state & ControlMask) != 0;
|
||||
irrevent.KeyInput.Shift = (event.xkey.state & ShiftMask) != 0;
|
||||
|
||||
event.xkey.state &= ~(ControlMask|ShiftMask); // ignore shift-ctrl states for figuring out the key
|
||||
XLookupString(&event.xkey, buf, sizeof(buf), &mp.X11Key, NULL);
|
||||
const s32 idx = KeyMap.binary_search(mp);
|
||||
if (idx != -1)
|
||||
if ( XInputContext )
|
||||
{
|
||||
irrevent.KeyInput.Key = (EKEY_CODE)KeyMap[idx].Win32Key;
|
||||
}
|
||||
else
|
||||
{
|
||||
irrevent.KeyInput.Key = (EKEY_CODE)0;
|
||||
}
|
||||
if (irrevent.KeyInput.Key == 0)
|
||||
{
|
||||
// 1:1 mapping to windows-keys would require testing for keyboard type (us, ger, ...)
|
||||
// So unless we do that we will have some unknown keys here.
|
||||
if (idx == -1)
|
||||
wchar_t buf[8]={0};
|
||||
Status status;
|
||||
int strLen = XwcLookupString(XInputContext, &event.xkey, buf, sizeof(buf), &mp.X11Key, &status);
|
||||
if ( status == XBufferOverflow )
|
||||
{
|
||||
os::Printer::log("Could not find EKEY_CODE, using orig. X11 keycode instead", core::stringc(event.xkey.keycode).c_str(), ELL_INFORMATION);
|
||||
os::Printer::log("XwcLookupString needs a larger buffer", ELL_INFORMATION);
|
||||
}
|
||||
if ( strLen > 0 && (status == XLookupChars || status == XLookupBoth) )
|
||||
{
|
||||
if ( strLen > 1 )
|
||||
os::Printer::log("Additional returned characters dropped", ELL_INFORMATION);
|
||||
irrevent.KeyInput.Char = buf[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
os::Printer::log("EKEY_CODE is 0, using orig. X11 keycode instead", core::stringc(event.xkey.keycode).c_str(), ELL_INFORMATION);
|
||||
irrevent.KeyInput.Char = 0;
|
||||
}
|
||||
// Any value is better than none, that allows at least using the keys.
|
||||
// Worst case is that some keys will be identical, still better than _all_
|
||||
// unknown keys being identical.
|
||||
irrevent.KeyInput.Key = (EKEY_CODE)event.xkey.keycode;
|
||||
}
|
||||
else // Old version without InputContext. Does not support i18n, but good to have as fallback.
|
||||
{
|
||||
union
|
||||
{
|
||||
char buf[8];
|
||||
wchar_t wbuf[2];
|
||||
} tmp = {0};
|
||||
XLookupString(&event.xkey, tmp.buf, sizeof(tmp.buf), &mp.X11Key, NULL);
|
||||
irrevent.KeyInput.Char = tmp.wbuf[0];
|
||||
}
|
||||
|
||||
irrevent.EventType = irr::EET_KEY_INPUT_EVENT;
|
||||
irrevent.KeyInput.PressedDown = true;
|
||||
irrevent.KeyInput.Control = (event.xkey.state & ControlMask) != 0;
|
||||
irrevent.KeyInput.Shift = (event.xkey.state & ShiftMask) != 0;
|
||||
irrevent.KeyInput.Key = getKeyCode(event);
|
||||
|
||||
postEventFromUser(irrevent);
|
||||
}
|
||||
@ -2052,7 +2185,7 @@ bool CIrrDeviceLinux::activateJoysticks(core::array<SJoystickInfo> & joystickInf
|
||||
#ifdef __FreeBSD__
|
||||
info.axes=2;
|
||||
info.buttons=2;
|
||||
#else
|
||||
#elif defined(__linux__)
|
||||
ioctl( info.fd, JSIOCGAXES, &(info.axes) );
|
||||
ioctl( info.fd, JSIOCGBUTTONS, &(info.buttons) );
|
||||
fcntl( info.fd, F_SETFL, O_NONBLOCK );
|
||||
@ -2074,7 +2207,7 @@ bool CIrrDeviceLinux::activateJoysticks(core::array<SJoystickInfo> & joystickInf
|
||||
returnInfo.Axes = info.axes;
|
||||
returnInfo.Buttons = info.buttons;
|
||||
|
||||
#ifndef __FreeBSD__
|
||||
#if !defined(__FreeBSD__) && !defined(__OpenBSD__)
|
||||
char name[80];
|
||||
ioctl( info.fd, JSIOCGNAME(80), name);
|
||||
returnInfo.Name = name;
|
||||
@ -2119,7 +2252,7 @@ void CIrrDeviceLinux::pollJoysticks()
|
||||
info.persistentData.JoystickEvent.Axis[0] = js.x; /* X axis */
|
||||
info.persistentData.JoystickEvent.Axis[1] = js.y; /* Y axis */
|
||||
}
|
||||
#else
|
||||
#elif defined(__linux__)
|
||||
struct js_event event;
|
||||
while (sizeof(event) == read(info.fd, &event, sizeof(event)))
|
||||
{
|
||||
|
@ -153,6 +153,12 @@ namespace irr
|
||||
bool restoreResolution();
|
||||
bool changeResolution();
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_X11_
|
||||
bool createInputContext();
|
||||
void destroyInputContext();
|
||||
EKEY_CODE getKeyCode(XEvent &event);
|
||||
#endif
|
||||
|
||||
//! Implementation of the linux cursor control
|
||||
class CCursorControl : public gui::ICursorControl
|
||||
{
|
||||
@ -390,6 +396,8 @@ namespace irr
|
||||
XSetWindowAttributes attributes;
|
||||
XSizeHints* StdHints;
|
||||
XImage* SoftwareImage;
|
||||
XIM XInputMethod;
|
||||
XIC XInputContext;
|
||||
mutable core::stringc Clipboard;
|
||||
#ifdef _IRR_LINUX_X11_VIDMODE_
|
||||
XF86VidModeModeInfo oldVideoMode;
|
||||
|
@ -478,7 +478,7 @@ bool CIrrDeviceSDL::run()
|
||||
joyevent.JoystickEvent.ButtonStates |= (SDL_JoystickGetButton(joystick, j)<<j);
|
||||
|
||||
// query all axes, already in correct range
|
||||
const int numAxes = core::min_(SDL_JoystickNumAxes(joystick), SEvent::SJoystickEvent::NUMBER_OF_AXES);
|
||||
const int numAxes = core::min_(SDL_JoystickNumAxes(joystick), static_cast<int>(SEvent::SJoystickEvent::NUMBER_OF_AXES));
|
||||
joyevent.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_X]=0;
|
||||
joyevent.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_Y]=0;
|
||||
joyevent.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_Z]=0;
|
||||
|
@ -34,6 +34,9 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <imm.h>
|
||||
#pragma comment(lib, "imm32.lib")
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace video
|
||||
@ -692,6 +695,28 @@ irr::CIrrDeviceWin32* getDeviceFromHWnd(HWND hWnd)
|
||||
}
|
||||
|
||||
|
||||
namespace irr
|
||||
{
|
||||
void updateICPos(void* hWnd, s32 x, s32 y, s32 height)
|
||||
{
|
||||
COMPOSITIONFORM cf;
|
||||
HWND hwnd = (HWND)hWnd;
|
||||
HIMC hIMC = ImmGetContext(hwnd);
|
||||
|
||||
if(hIMC)
|
||||
{
|
||||
cf.dwStyle = CFS_POINT;
|
||||
cf.ptCurrentPos.x = x;
|
||||
cf.ptCurrentPos.y = y - height;
|
||||
|
||||
ImmSetCompositionWindow(hIMC, &cf);
|
||||
|
||||
ImmReleaseContext(hwnd, hIMC);
|
||||
}
|
||||
}
|
||||
} // end of namespace irr
|
||||
|
||||
|
||||
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
#ifndef WM_MOUSEWHEEL
|
||||
@ -802,6 +827,16 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m->irrMessage == irr::EMIE_LMOUSE_PRESSED_DOWN || m->irrMessage == irr::EMIE_LMOUSE_LEFT_UP)
|
||||
{
|
||||
event.EventType = irr::EET_IMPUT_METHOD_EVENT;
|
||||
event.InputMethodEvent.Event = irr::EIME_CHANGE_POS;
|
||||
event.InputMethodEvent.Handle = hWnd;
|
||||
|
||||
if (dev)
|
||||
dev->postEventFromUser(event);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -818,6 +853,30 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
case WM_ERASEBKGND:
|
||||
return 0;
|
||||
|
||||
case WM_IME_CHAR:
|
||||
{
|
||||
event.EventType = irr::EET_IMPUT_METHOD_EVENT;
|
||||
event.InputMethodEvent.Event = irr::EIME_CHAR_INPUT;
|
||||
event.InputMethodEvent.Handle = hWnd;
|
||||
|
||||
event.KeyInput.Char = 0;
|
||||
event.KeyInput.Key = irr::KEY_OEM_CLEAR;
|
||||
event.KeyInput.Shift = 0;
|
||||
event.KeyInput.Control = 0;
|
||||
|
||||
char bits[2] = { (char)((wParam & 0xff00) >> 8), (char)(wParam & 0xff) };
|
||||
if (bits[0] == 0)
|
||||
event.InputMethodEvent.Char = (wchar_t)wParam;
|
||||
else
|
||||
MultiByteToWideChar(CP_OEMCP, MB_PRECOMPOSED, bits, 2, &event.InputMethodEvent.Char, 1);
|
||||
|
||||
dev = getDeviceFromHWnd(hWnd);
|
||||
if (dev)
|
||||
dev->postEventFromUser(event);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
case WM_SYSKEYDOWN:
|
||||
case WM_SYSKEYUP:
|
||||
case WM_KEYDOWN:
|
||||
@ -879,6 +938,13 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
event.KeyInput.Control = 0;
|
||||
|
||||
dev = getDeviceFromHWnd(hWnd);
|
||||
if (dev)
|
||||
dev->postEventFromUser(event);
|
||||
|
||||
event.EventType = irr::EET_IMPUT_METHOD_EVENT;
|
||||
event.InputMethodEvent.Event = irr::EIME_CHANGE_POS;
|
||||
event.InputMethodEvent.Handle = hWnd;
|
||||
|
||||
if (dev)
|
||||
dev->postEventFromUser(event);
|
||||
|
||||
@ -932,6 +998,12 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
dev->switchToFullScreen();
|
||||
}
|
||||
}
|
||||
event.EventType = irr::EET_IMPUT_METHOD_EVENT;
|
||||
event.InputMethodEvent.Event = irr::EIME_CHANGE_POS;
|
||||
event.InputMethodEvent.Handle = hWnd;
|
||||
|
||||
if (dev)
|
||||
dev->postEventFromUser(event);
|
||||
break;
|
||||
|
||||
case WM_USER:
|
||||
@ -1115,6 +1187,9 @@ CIrrDeviceWin32::CIrrDeviceWin32(const SIrrlichtCreationParameters& params)
|
||||
|
||||
// inform driver about the window size etc.
|
||||
resizeIfNecessary();
|
||||
|
||||
// for reset the position of composition window
|
||||
updateICPos(HWnd, 0, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
@ -1870,6 +1945,8 @@ void CIrrDeviceWin32::handleSystemMessages()
|
||||
// No message translation because we don't use WM_CHAR and it would conflict with our
|
||||
// deadkey handling.
|
||||
|
||||
TranslateMessage(&msg);
|
||||
|
||||
if (ExternalWindow && msg.hwnd == HWnd)
|
||||
WndProc(HWnd, msg.message, msg.wParam, msg.lParam);
|
||||
else
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#if !defined(_IRR_SOLARIS_PLATFORM_) && !defined(__CYGWIN__)
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
@ -52,6 +53,37 @@ const core::stringc& COSOperator::getOperatingSystemVersion() const
|
||||
|
||||
|
||||
//! copies text to the clipboard
|
||||
#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_)
|
||||
void COSOperator::copyToClipboard(const wchar_t* text) const
|
||||
{
|
||||
if (wcslen(text)==0)
|
||||
return;
|
||||
|
||||
// Windows version
|
||||
#if defined(_IRR_XBOX_PLATFORM_)
|
||||
#elif defined(_IRR_WINDOWS_API_)
|
||||
if (!OpenClipboard(NULL) || text == 0)
|
||||
return;
|
||||
|
||||
EmptyClipboard();
|
||||
|
||||
HGLOBAL clipbuffer;
|
||||
wchar_t * buffer;
|
||||
|
||||
clipbuffer = GlobalAlloc(GMEM_DDESHARE, wcslen(text)*sizeof(wchar_t) + sizeof(wchar_t));
|
||||
buffer = (wchar_t*)GlobalLock(clipbuffer);
|
||||
|
||||
wcscpy(buffer, text);
|
||||
|
||||
GlobalUnlock(clipbuffer);
|
||||
SetClipboardData(CF_UNICODETEXT, clipbuffer); //Windwos converts between CF_UNICODETEXT and CF_TEXT automatically.
|
||||
CloseClipboard();
|
||||
|
||||
#else
|
||||
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
void COSOperator::copyToClipboard(const c8* text) const
|
||||
{
|
||||
if (strlen(text)==0)
|
||||
@ -89,10 +121,34 @@ void COSOperator::copyToClipboard(const c8* text) const
|
||||
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//! gets text from the clipboard
|
||||
//! \return Returns 0 if no string is in there.
|
||||
#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_)
|
||||
const wchar_t* COSOperator::getTextFromClipboard() const
|
||||
{
|
||||
#if defined(_IRR_XBOX_PLATFORM_)
|
||||
return 0;
|
||||
#elif defined(_IRR_WINDOWS_API_)
|
||||
if (!OpenClipboard(NULL))
|
||||
return 0;
|
||||
|
||||
wchar_t * buffer = 0;
|
||||
|
||||
HANDLE hData = GetClipboardData( CF_UNICODETEXT ); //Windwos converts between CF_UNICODETEXT and CF_TEXT automatically.
|
||||
buffer = (wchar_t*)GlobalLock( hData );
|
||||
GlobalUnlock( hData );
|
||||
CloseClipboard();
|
||||
return buffer;
|
||||
|
||||
#else
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
const c8* COSOperator::getTextFromClipboard() const
|
||||
{
|
||||
#if defined(_IRR_XBOX_PLATFORM_)
|
||||
@ -122,6 +178,7 @@ const c8* COSOperator::getTextFromClipboard() const
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
bool COSOperator::getProcessorSpeedMHz(u32* MHz) const
|
||||
|
@ -27,11 +27,19 @@ public:
|
||||
virtual const core::stringc& getOperatingSystemVersion() const;
|
||||
|
||||
//! copies text to the clipboard
|
||||
#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_)
|
||||
virtual void copyToClipboard(const wchar_t* text) const;
|
||||
#else
|
||||
virtual void copyToClipboard(const c8* text) const;
|
||||
#endif
|
||||
|
||||
//! gets text from the clipboard
|
||||
//! \return Returns 0 if no string is in there.
|
||||
#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_)
|
||||
virtual const wchar_t* getTextFromClipboard() const;
|
||||
#else
|
||||
virtual const c8* getTextFromClipboard() const;
|
||||
#endif
|
||||
|
||||
//! gets the processor speed in megahertz
|
||||
//! \param Mhz:
|
||||
|
@ -805,13 +805,15 @@ bool COpenGLDriver::genericDriverInit()
|
||||
|
||||
Params.HandleSRGB &= ((FeatureAvailable[IRR_ARB_framebuffer_sRGB] || FeatureAvailable[IRR_EXT_framebuffer_sRGB]) &&
|
||||
FeatureAvailable[IRR_EXT_texture_sRGB]);
|
||||
#if defined(GL_ARB_framebuffer_sRGB)
|
||||
if (Params.HandleSRGB)
|
||||
glEnable(GL_FRAMEBUFFER_SRGB);
|
||||
#elif defined(GL_EXT_framebuffer_sRGB)
|
||||
if (Params.HandleSRGB)
|
||||
glEnable(GL_FRAMEBUFFER_SRGB_EXT);
|
||||
#endif
|
||||
|
||||
glDisable(GL_FRAMEBUFFER_SRGB);
|
||||
//#if defined(GL_ARB_framebuffer_sRGB)
|
||||
// if (Params.HandleSRGB)
|
||||
// glEnable(GL_FRAMEBUFFER_SRGB);
|
||||
//#elif defined(GL_EXT_framebuffer_sRGB)
|
||||
// if (Params.HandleSRGB)
|
||||
// glEnable(GL_FRAMEBUFFER_SRGB_EXT);
|
||||
//#endif
|
||||
|
||||
// This is a fast replacement for NORMALIZE_NORMALS
|
||||
// if ((Version>101) || FeatureAvailable[IRR_EXT_rescale_normal])
|
||||
|
@ -274,15 +274,15 @@ GLint COpenGLTexture::getOpenGLFormatAndParametersFromColorFormat(ECOLOR_FORMAT
|
||||
internalformat = GL_RGBA8;
|
||||
}
|
||||
}
|
||||
#if defined(GL_ARB_framebuffer_sRGB) || defined(GL_EXT_framebuffer_sRGB)
|
||||
if (Driver->Params.HandleSRGB)
|
||||
{
|
||||
if (internalformat==GL_RGBA)
|
||||
internalformat=GL_SRGB_ALPHA_EXT;
|
||||
else if (internalformat==GL_RGB)
|
||||
internalformat=GL_SRGB_EXT;
|
||||
}
|
||||
#endif
|
||||
//#if defined(GL_ARB_framebuffer_sRGB) || defined(GL_EXT_framebuffer_sRGB)
|
||||
// if (Driver->Params.HandleSRGB)
|
||||
// {
|
||||
// if (internalformat==GL_RGBA)
|
||||
// internalformat=GL_SRGB_ALPHA_EXT;
|
||||
// else if (internalformat==GL_RGB)
|
||||
// internalformat=GL_SRGB_EXT;
|
||||
// }
|
||||
//#endif
|
||||
return internalformat;
|
||||
}
|
||||
|
||||
|
@ -22,10 +22,14 @@
|
||||
#include <libkern/OSByteOrder.h>
|
||||
#define bswap_16(X) OSReadSwapInt16(&X,0)
|
||||
#define bswap_32(X) OSReadSwapInt32(&X,0)
|
||||
#elif defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||
#elif defined(__FreeBSD__)
|
||||
#include <sys/endian.h>
|
||||
#define bswap_16(X) bswap16(X)
|
||||
#define bswap_32(X) bswap32(X)
|
||||
#elif defined(__OpenBSD__)
|
||||
#include <endian.h>
|
||||
#define bswap_16(X) swap16(X)
|
||||
#define bswap_32(X) swap32(X)
|
||||
#elif !defined(_IRR_SOLARIS_PLATFORM_) && !defined(__PPC__) && !defined(_IRR_WINDOWS_API_)
|
||||
#include <byteswap.h>
|
||||
#else
|
||||
|
@ -42,18 +42,6 @@
|
||||
#include <hidsdi.h>
|
||||
#include <setupapi.h>
|
||||
|
||||
#ifdef __MINGW32__
|
||||
/* this prototype is missing from the mingw headers so we must add it
|
||||
or suffer linker errors. */
|
||||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif
|
||||
HIDAPI BOOL NTAPI HidD_SetOutputReport(HANDLE, PVOID, ULONG);
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
int wiiuse_os_find(struct wiimote_t** wm, int max_wiimotes, int timeout) {
|
||||
GUID device_id;
|
||||
HANDLE dev;
|
||||
|
@ -1,5 +1,5 @@
|
||||
# Modify this file to change the last-modified date when you add/remove a file.
|
||||
# This will then trigger a new cmake run automatically.
|
||||
# Modify this file to change the last-modified date when you add/remove a file.
|
||||
# This will then trigger a new cmake run automatically.
|
||||
file(GLOB_RECURSE STK_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.hpp")
|
||||
file(GLOB_RECURSE STK_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp")
|
||||
file(GLOB_RECURSE STK_SHADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "data/shaders/*")
|
||||
|
@ -269,7 +269,7 @@ void PlayerManager::save()
|
||||
if(m_current_player)
|
||||
{
|
||||
players_file << L" <current player=\""
|
||||
<< StringUtils::xmlEncode(m_current_player->getName()) << L"\"/>\n";
|
||||
<< StringUtils::xmlEncode(m_current_player->getName(true/*ignoreRTL*/)) << L"\"/>\n";
|
||||
}
|
||||
|
||||
// Save all non-guest players
|
||||
@ -327,7 +327,7 @@ void PlayerManager::enforceCurrentPlayer()
|
||||
if (!player->isGuestAccount())
|
||||
{
|
||||
Log::info("PlayerManager", "Enforcing current player '%ls'.",
|
||||
player->getName().c_str() );
|
||||
player->getName(true/*ignoreRTL*/).c_str());
|
||||
m_current_player = player;
|
||||
return;
|
||||
}
|
||||
@ -341,7 +341,7 @@ void PlayerManager::enforceCurrentPlayer()
|
||||
if (!player->isGuestAccount())
|
||||
{
|
||||
Log::info("PlayerManager", "Enforcing current player '%s'.",
|
||||
player->getName().c_str());
|
||||
player->getName(true/*ignoreRTL*/).c_str());
|
||||
m_current_player = player;
|
||||
return;
|
||||
}
|
||||
@ -454,7 +454,7 @@ PlayerProfile *PlayerManager::getPlayer(const irr::core::stringw &name)
|
||||
{
|
||||
for (PlayerProfile* player : m_all_players)
|
||||
{
|
||||
if(player->getName()==name)
|
||||
if(player->getName(true/*ignoreRTL*/)==name)
|
||||
return player;
|
||||
}
|
||||
return NULL;
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "utils/leak_check.hpp"
|
||||
#include "utils/no_copy.hpp"
|
||||
#include "utils/types.hpp"
|
||||
#include "utils/translation.hpp"
|
||||
|
||||
#include <irrString.h>
|
||||
using namespace irr;
|
||||
@ -154,10 +155,17 @@ public:
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the name of this player. */
|
||||
core::stringw getName() const
|
||||
const core::stringw getName(bool ignore_rtl = false) const
|
||||
{
|
||||
assert(m_magic_number == 0xABCD1234);
|
||||
return m_local_name.c_str();
|
||||
if (ignore_rtl)
|
||||
return m_local_name;
|
||||
else
|
||||
{
|
||||
const core::stringw fribidized_name =
|
||||
translations->fribidize(m_local_name);
|
||||
return fribidized_name;
|
||||
}
|
||||
} // getName
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
@ -171,9 +179,16 @@ public:
|
||||
} // isGuestAccount
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the last used online name. */
|
||||
const core::stringw& getLastOnlineName() const
|
||||
const core::stringw getLastOnlineName(bool ignore_rtl = false) const
|
||||
{
|
||||
return m_last_online_name;
|
||||
if (ignore_rtl)
|
||||
return m_last_online_name;
|
||||
else
|
||||
{
|
||||
const core::stringw fribidized_name =
|
||||
translations->fribidize(m_last_online_name);
|
||||
return fribidized_name;
|
||||
}
|
||||
} // getLastOnlineName
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets the last used online name. */
|
||||
|
@ -27,7 +27,6 @@
|
||||
#include "io/xml_node.hpp"
|
||||
#include "items/item.hpp"
|
||||
#include "karts/kart_properties.hpp"
|
||||
#include "karts/player_difficulty.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
STKConfig* stk_config=0;
|
||||
@ -119,19 +118,8 @@ void STKConfig::load(const std::string &filename)
|
||||
}
|
||||
|
||||
CHECK_NEG(m_max_karts, "<karts max=..." );
|
||||
CHECK_NEG(m_parachute_friction, "parachute-friction" );
|
||||
CHECK_NEG(m_parachute_lbound_fraction, "parachute-lbound-fraction" );
|
||||
CHECK_NEG(m_parachute_ubound_fraction, "parachute-ubound-fraction" );
|
||||
CHECK_NEG(m_parachute_max_speed, "parachute-max-speed" );
|
||||
CHECK_NEG(m_parachute_time, "parachute-time" );
|
||||
CHECK_NEG(m_parachute_time_other, "parachute-time-other" );
|
||||
CHECK_NEG(m_bomb_time, "bomb-time" );
|
||||
CHECK_NEG(m_bomb_time_increase, "bomb-time-increase" );
|
||||
CHECK_NEG(m_anvil_time, "anvil-time" );
|
||||
CHECK_NEG(m_anvil_weight, "anvil-weight" );
|
||||
CHECK_NEG(m_item_switch_time, "item-switch-time" );
|
||||
CHECK_NEG(m_bubblegum_counter, "bubblegum disappear counter");
|
||||
CHECK_NEG(m_bubblegum_shield_time, "bubblegum shield-time" );
|
||||
CHECK_NEG(m_explosion_impulse_objects, "explosion-impulse-objects" );
|
||||
CHECK_NEG(m_max_skidmarks, "max-skidmarks" );
|
||||
CHECK_NEG(m_min_kart_version, "<kart-version min...>" );
|
||||
@ -163,18 +151,13 @@ void STKConfig::load(const std::string &filename)
|
||||
*/
|
||||
void STKConfig::init_defaults()
|
||||
{
|
||||
m_anvil_weight = m_parachute_friction =
|
||||
m_parachute_time = m_parachute_lbound_fraction =
|
||||
m_parachute_time_other = m_anvil_speed_factor =
|
||||
m_bomb_time = m_bomb_time_increase =
|
||||
m_anvil_time = m_music_credit_time =
|
||||
m_bomb_time = m_bomb_time_increase =
|
||||
m_explosion_impulse_objects = m_music_credit_time =
|
||||
m_delay_finish_time = m_skid_fadeout_time =
|
||||
m_near_ground = m_item_switch_time =
|
||||
m_smooth_angle_limit = m_parachute_ubound_fraction =
|
||||
m_penalty_time = m_explosion_impulse_objects =
|
||||
m_parachute_max_speed = UNDEFINED;
|
||||
m_smooth_angle_limit = m_penalty_time =
|
||||
UNDEFINED;
|
||||
m_bubblegum_counter = -100;
|
||||
m_bubblegum_shield_time = -100;
|
||||
m_shield_restrict_weapos = false;
|
||||
m_max_karts = -100;
|
||||
m_max_skidmarks = -100;
|
||||
@ -310,23 +293,6 @@ void STKConfig::getAllData(const XMLNode * root)
|
||||
credits_node->get("music", &m_music_credit_time);
|
||||
|
||||
|
||||
if(const XMLNode *anvil_node= root->getNode("anvil"))
|
||||
{
|
||||
anvil_node->get("weight", &m_anvil_weight );
|
||||
anvil_node->get("speed-factor", &m_anvil_speed_factor);
|
||||
anvil_node->get("time", &m_anvil_time );
|
||||
}
|
||||
|
||||
if(const XMLNode *parachute_node= root->getNode("parachute"))
|
||||
{
|
||||
parachute_node->get("friction", &m_parachute_friction );
|
||||
parachute_node->get("time", &m_parachute_time );
|
||||
parachute_node->get("time-other", &m_parachute_time_other );
|
||||
parachute_node->get("lbound-fraction", &m_parachute_lbound_fraction);
|
||||
parachute_node->get("ubound-fraction", &m_parachute_ubound_fraction);
|
||||
parachute_node->get("max-speed", &m_parachute_max_speed );
|
||||
}
|
||||
|
||||
if(const XMLNode *bomb_node= root->getNode("bomb"))
|
||||
{
|
||||
bomb_node->get("time", &m_bomb_time);
|
||||
@ -359,7 +325,6 @@ void STKConfig::getAllData(const XMLNode * root)
|
||||
if(const XMLNode *bubblegum_node= root->getNode("bubblegum"))
|
||||
{
|
||||
bubblegum_node->get("disappear-counter", &m_bubblegum_counter );
|
||||
bubblegum_node->get("shield-time", &m_bubblegum_shield_time );
|
||||
bubblegum_node->get("restrict-weapons", &m_shield_restrict_weapos);
|
||||
}
|
||||
|
||||
@ -415,14 +380,6 @@ void STKConfig::getAllData(const XMLNode * root)
|
||||
m_kart_properties[type->getName()]->copyFrom(m_default_kart_properties);
|
||||
m_kart_properties[type->getName()]->getAllData(type);
|
||||
}
|
||||
|
||||
child_node = node->getNode("difficulties");
|
||||
for (unsigned int i = 0; i < child_node->getNumNodes(); ++i)
|
||||
{
|
||||
const XMLNode* type = child_node->getNode(i);
|
||||
m_player_difficulties[i] = new PlayerDifficulty();
|
||||
m_player_difficulties[i]->getAllData(type);
|
||||
}
|
||||
} // getAllData
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -34,7 +34,6 @@
|
||||
#include <map>
|
||||
|
||||
class KartProperties;
|
||||
class PlayerDifficulty;
|
||||
class MusicInformation;
|
||||
class XMLNode;
|
||||
|
||||
@ -51,8 +50,6 @@ protected:
|
||||
/** Default kart properties. */
|
||||
KartProperties *m_default_kart_properties;
|
||||
std::map<std::string, KartProperties*> m_kart_properties;
|
||||
/** Per-player difficulties. */
|
||||
PlayerDifficulty* m_player_difficulties[PLAYER_DIFFICULTY_COUNT];
|
||||
|
||||
public:
|
||||
/** What to do if a kart already has a powerup when it hits a bonus box:
|
||||
@ -66,26 +63,12 @@ public:
|
||||
m_same_powerup_mode;
|
||||
|
||||
static float UNDEFINED;
|
||||
float m_anvil_weight; /**<Additional kart weight if anvil is
|
||||
attached. */
|
||||
float m_anvil_speed_factor; /**<Speed decrease when attached first. */
|
||||
float m_parachute_friction; /**<Increased parachute air friction. */
|
||||
float m_parachute_ubound_fraction; /**<Upper bound fraction of speed when
|
||||
lost will detach parachute. */
|
||||
float m_parachute_lbound_fraction; /**<Lower bound fraction of speed when
|
||||
lost will detach parachute. */
|
||||
float m_parachute_max_speed; /**<Max speed to rate current speed */
|
||||
float m_parachute_time; /**<Time a parachute is active. */
|
||||
float m_parachute_time_other; /**<Time a parachute attached to other
|
||||
karts is active. */
|
||||
float m_bomb_time; /**<Time before a bomb explodes. */
|
||||
float m_bomb_time_increase; /**<Time added to bomb timer when it's
|
||||
passed on. */
|
||||
float m_anvil_time; /**<Time an anvil is active. */
|
||||
float m_item_switch_time; /**< Time items will be switched. */
|
||||
int m_bubblegum_counter; /**< How many times bubble gums must be
|
||||
driven over before they disappear. */
|
||||
float m_bubblegum_shield_time; /**<How long a bubble gum shield lasts. */
|
||||
bool m_shield_restrict_weapos; /**<Wether weapon usage is punished. */
|
||||
float m_explosion_impulse_objects; /**<Impulse of explosion on moving
|
||||
objects, e.g. road cones, ... */
|
||||
@ -199,10 +182,6 @@ public:
|
||||
{
|
||||
return *m_kart_properties.at(type);
|
||||
} // getKartProperties
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
const PlayerDifficulty * getPlayerDifficulty(PerPlayerDifficulty difficulty)
|
||||
{ return m_player_difficulties[difficulty]; }
|
||||
}
|
||||
; // STKConfig
|
||||
|
||||
|
@ -380,7 +380,7 @@ void Camera::smoothMoveCamera(float dt)
|
||||
// Smoothly interpolate towards the position and target
|
||||
const KartProperties *kp = m_kart->getKartProperties();
|
||||
float max_increase_with_zipper = kp->getZipperMaxSpeedIncrease();
|
||||
float max_speed_without_zipper = kp->getMaxSpeed();
|
||||
float max_speed_without_zipper = kp->getEngineMaxSpeed();
|
||||
float current_speed = m_kart->getSpeed();
|
||||
|
||||
const Skidding *ks = m_kart->getSkidding();
|
||||
@ -469,7 +469,7 @@ void Camera::getCameraSettings(float *above_kart, float *cam_angle,
|
||||
else
|
||||
{
|
||||
*above_kart = 0.75f;
|
||||
*cam_angle = kp->getCameraForwardUpAngle();
|
||||
*cam_angle = kp->getCameraForwardUpAngle() * DEGREE_TO_RAD;
|
||||
*distance = -m_distance;
|
||||
}
|
||||
float steering = m_kart->getSteerPercent()
|
||||
@ -484,7 +484,7 @@ void Camera::getCameraSettings(float *above_kart, float *cam_angle,
|
||||
case CM_REVERSE: // Same as CM_NORMAL except it looks backwards
|
||||
{
|
||||
*above_kart = 0.75f;
|
||||
*cam_angle = kp->getCameraBackwardUpAngle();
|
||||
*cam_angle = kp->getCameraBackwardUpAngle() * DEGREE_TO_RAD;
|
||||
*sideway = 0;
|
||||
*distance = 2.0f*m_distance;
|
||||
*smoothing = false;
|
||||
@ -843,8 +843,7 @@ void Camera::handleEndCamera(float dt)
|
||||
}
|
||||
case EndCameraInformation::EC_AHEAD_OF_KART:
|
||||
{
|
||||
const KartProperties *kp=m_kart->getKartProperties();
|
||||
float cam_angle = kp->getCameraBackwardUpAngle();
|
||||
float cam_angle = m_kart->getKartProperties()->getCameraBackwardUpAngle() * DEGREE_TO_RAD;
|
||||
|
||||
positionCamera(dt, /*above_kart*/0.75f,
|
||||
cam_angle, /*side_way*/0,
|
||||
|
@ -36,6 +36,7 @@ void CentralVideoSettings::init()
|
||||
hasBuffserStorage = false;
|
||||
hasDrawIndirect = false;
|
||||
hasComputeShaders = false;
|
||||
hasArraysOfArrays = false;
|
||||
hasTextureStorage = false;
|
||||
hasTextureView = false;
|
||||
hasBindlessTexture = false;
|
||||
@ -46,10 +47,11 @@ void CentralVideoSettings::init()
|
||||
hasTextureCompression = false;
|
||||
hasUBO = false;
|
||||
hasGS = false;
|
||||
m_GI_has_artifact = false;
|
||||
|
||||
m_GI_has_artifact = false;
|
||||
m_need_rh_workaround = false;
|
||||
m_need_srgb_workaround = false;
|
||||
m_need_srgb_visual_workaround = false;
|
||||
|
||||
// Call to glGetIntegerv should not be made if --no-graphics is used
|
||||
if (!ProfileWorld::isNoGraphics())
|
||||
@ -102,6 +104,11 @@ void CentralVideoSettings::init()
|
||||
hasComputeShaders = true;
|
||||
Log::info("GLDriver", "ARB Compute Shader Present");
|
||||
}
|
||||
if (!GraphicsRestrictions::isDisabled(GraphicsRestrictions::GR_ARRAYS_OF_ARRAYS) &&
|
||||
hasGLExtension("GL_ARB_arrays_of_arrays")) {
|
||||
hasArraysOfArrays = true;
|
||||
Log::info("GLDriver", "ARB Arrays of Arrays Present");
|
||||
}
|
||||
if (!GraphicsRestrictions::isDisabled(GraphicsRestrictions::GR_TEXTURE_STORAGE) &&
|
||||
hasGLExtension("GL_ARB_texture_storage")) {
|
||||
hasTextureStorage = true;
|
||||
@ -179,6 +186,16 @@ void CentralVideoSettings::init()
|
||||
// Bindless textures are all treated RGB even sRGB one
|
||||
m_need_srgb_workaround = true;
|
||||
}
|
||||
|
||||
// Check if visual is sRGB-capable
|
||||
if (GraphicsRestrictions::isDisabled(GraphicsRestrictions::GR_FRAMEBUFFER_SRGB_CAPABLE) &&
|
||||
m_glsl == true)
|
||||
{
|
||||
GLint param = GL_SRGB;
|
||||
glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, GL_BACK_LEFT,
|
||||
GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING, ¶m);
|
||||
m_need_srgb_visual_workaround = (param != GL_SRGB);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -207,6 +224,11 @@ bool CentralVideoSettings::needsRGBBindlessWorkaround() const
|
||||
return m_need_srgb_workaround;
|
||||
}
|
||||
|
||||
bool CentralVideoSettings::needsSRGBCapableVisualWorkaround() const
|
||||
{
|
||||
return m_need_srgb_visual_workaround;
|
||||
}
|
||||
|
||||
bool CentralVideoSettings::isARBGeometryShader4Usable() const
|
||||
{
|
||||
return hasGS;
|
||||
@ -247,6 +269,11 @@ bool CentralVideoSettings::isARBComputeShaderUsable() const
|
||||
return hasComputeShaders;
|
||||
}
|
||||
|
||||
bool CentralVideoSettings::isARBArraysOfArraysUsable() const
|
||||
{
|
||||
return hasArraysOfArrays;
|
||||
}
|
||||
|
||||
bool CentralVideoSettings::isARBTextureStorageUsable() const
|
||||
{
|
||||
return hasTextureStorage;
|
||||
@ -299,7 +326,7 @@ bool CentralVideoSettings::supportsIndirectInstancingRendering() const
|
||||
|
||||
bool CentralVideoSettings::supportsComputeShadersFiltering() const
|
||||
{
|
||||
return isARBBufferStorageUsable() && isARBImageLoadStoreUsable() && isARBComputeShaderUsable();
|
||||
return isARBBufferStorageUsable() && isARBImageLoadStoreUsable() && isARBComputeShaderUsable() && isARBArraysOfArraysUsable();
|
||||
}
|
||||
|
||||
bool CentralVideoSettings::supportsAsyncInstanceUpload() const
|
||||
|
@ -30,6 +30,7 @@ private:
|
||||
bool hasDrawIndirect;
|
||||
bool hasBuffserStorage;
|
||||
bool hasComputeShaders;
|
||||
bool hasArraysOfArrays;
|
||||
bool hasTextureStorage;
|
||||
bool hasTextureView;
|
||||
bool hasBindlessTexture;
|
||||
@ -43,6 +44,7 @@ private:
|
||||
|
||||
bool m_need_rh_workaround;
|
||||
bool m_need_srgb_workaround;
|
||||
bool m_need_srgb_visual_workaround;
|
||||
bool m_GI_has_artifact;
|
||||
public:
|
||||
void init();
|
||||
@ -52,6 +54,7 @@ public:
|
||||
// Needs special handle ?
|
||||
bool needRHWorkaround() const;
|
||||
bool needsRGBBindlessWorkaround() const;
|
||||
bool needsSRGBCapableVisualWorkaround() const;
|
||||
|
||||
// Extension is available and safe to use
|
||||
bool isARBUniformBufferObjectUsable() const;
|
||||
@ -61,6 +64,7 @@ public:
|
||||
bool isARBTextureStorageUsable() const;
|
||||
bool isAMDVertexShaderLayerUsable() const;
|
||||
bool isARBComputeShaderUsable() const;
|
||||
bool isARBArraysOfArraysUsable() const;
|
||||
bool isARBBindlessTextureUsable() const;
|
||||
bool isARBBufferStorageUsable() const;
|
||||
bool isARBBaseInstanceUsable() const;
|
||||
|
@ -41,7 +41,7 @@ extern "C" {
|
||||
#elif defined(ANDROID)
|
||||
# include <GLES/gl.h>
|
||||
#elif defined(WIN32)
|
||||
# define _WINSOCKAPI_
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
#else
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
|
@ -48,6 +48,7 @@ namespace GraphicsRestrictions
|
||||
"ImageLoadStore",
|
||||
"BaseInstance",
|
||||
"ComputeShader",
|
||||
"ArraysOfArrays",
|
||||
"ShaderStorageBufferObject",
|
||||
"MultiDrawIndirect",
|
||||
"ShaderAtomicCounters",
|
||||
@ -59,6 +60,7 @@ namespace GraphicsRestrictions
|
||||
"HighDefinitionTextures",
|
||||
"AdvancedPipeline",
|
||||
"FramebufferSRGBWorking",
|
||||
"FramebufferSRGBCapable",
|
||||
"GI",
|
||||
};
|
||||
} // namespace Private
|
||||
|
@ -42,6 +42,7 @@ namespace GraphicsRestrictions
|
||||
GR_IMAGE_LOAD_STORE,
|
||||
GR_BASE_INSTANCE,
|
||||
GR_COMPUTE_SHADER,
|
||||
GR_ARRAYS_OF_ARRAYS,
|
||||
GR_SHADER_STORAGE_BUFFER_OBJECT,
|
||||
GR_MULTI_DRAW_INDIRECT,
|
||||
GR_SHADER_ATOMIC_COUNTERS,
|
||||
@ -53,6 +54,7 @@ namespace GraphicsRestrictions
|
||||
GR_HIGHDEFINITION_TEXTURES,
|
||||
GR_ADVANCED_PIPELINE,
|
||||
GR_FRAMEBUFFER_SRGB_WORKING,
|
||||
GR_FRAMEBUFFER_SRGB_CAPABLE,
|
||||
GR_GI,
|
||||
GR_COUNT /** MUST be last entry. */
|
||||
} ;
|
||||
|
@ -60,6 +60,7 @@
|
||||
#include "modes/profile_world.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "physics/physics.hpp"
|
||||
#include "scriptengine/property_animator.hpp"
|
||||
#include "states_screens/dialogs/confirm_resolution_dialog.hpp"
|
||||
#include "states_screens/state_manager.hpp"
|
||||
#include "tracks/track_manager.hpp"
|
||||
@ -85,6 +86,7 @@ please use the included version."
|
||||
using namespace irr;
|
||||
|
||||
#ifdef WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#if defined(__linux__) && !defined(ANDROID)
|
||||
@ -342,6 +344,8 @@ void IrrDriver::createListOfVideoModes()
|
||||
*/
|
||||
void IrrDriver::initDevice()
|
||||
{
|
||||
SIrrlichtCreationParameters params;
|
||||
|
||||
// If --no-graphics option was used, the null device can still be used.
|
||||
if (!ProfileWorld::isNoGraphics())
|
||||
{
|
||||
@ -424,7 +428,6 @@ void IrrDriver::initDevice()
|
||||
m_device->drop();
|
||||
m_device = NULL;
|
||||
|
||||
SIrrlichtCreationParameters params;
|
||||
params.ForceLegacyDevice = (UserConfigParams::m_force_legacy_device ||
|
||||
UserConfigParams::m_gamepad_visualisation);
|
||||
|
||||
@ -445,7 +448,8 @@ void IrrDriver::initDevice()
|
||||
params.WindowSize =
|
||||
core::dimension2du(UserConfigParams::m_width,
|
||||
UserConfigParams::m_height);
|
||||
|
||||
params.HandleSRGB = true;
|
||||
|
||||
/*
|
||||
switch ((int)UserConfigParams::m_antialiasing)
|
||||
{
|
||||
@ -503,6 +507,30 @@ void IrrDriver::initDevice()
|
||||
{
|
||||
Log::fatal("irr_driver", "Couldn't initialise irrlicht device. Quitting.\n");
|
||||
}
|
||||
|
||||
CVS->init();
|
||||
|
||||
// This is the ugly hack for intel driver on linux, which doesn't
|
||||
// use sRGB-capable visual, even if we request it. This causes
|
||||
// the screen to be darker than expected. It affects mesa 10.6 and newer.
|
||||
// Though we are able to force to use the proper format on mesa side by
|
||||
// setting WithAlphaChannel parameter.
|
||||
if (!ProfileWorld::isNoGraphics() && CVS->needsSRGBCapableVisualWorkaround())
|
||||
{
|
||||
Log::warn("irr_driver", "Created visual is not sRGB-capable. "
|
||||
"Re-creating device to workaround the issue.");
|
||||
m_device->closeDevice();
|
||||
m_device->drop();
|
||||
|
||||
params.WithAlphaChannel = true;
|
||||
|
||||
m_device = createDeviceEx(params);
|
||||
|
||||
if(!m_device)
|
||||
{
|
||||
Log::fatal("irr_driver", "Couldn't initialise irrlicht device. Quitting.\n");
|
||||
}
|
||||
}
|
||||
|
||||
m_scene_manager = m_device->getSceneManager();
|
||||
m_gui_env = m_device->getGUIEnvironment();
|
||||
@ -521,7 +549,7 @@ void IrrDriver::initDevice()
|
||||
(UserConfigParams::m_shadows_resolution < 512 ||
|
||||
UserConfigParams::m_shadows_resolution > 2048))
|
||||
{
|
||||
Log::warn("IrrDriver",
|
||||
Log::warn("irr_driver",
|
||||
"Invalid value for UserConfigParams::m_shadows_resolution : %i",
|
||||
(int)UserConfigParams::m_shadows_resolution);
|
||||
UserConfigParams::m_shadows_resolution = 0;
|
||||
@ -1868,7 +1896,7 @@ void IrrDriver::doScreenShot()
|
||||
video::IImage* image = m_video_driver->createScreenShot();
|
||||
if(!image)
|
||||
{
|
||||
Log::error("IrrDriver", "Could not create screen shot.");
|
||||
Log::error("irr_driver", "Could not create screen shot.");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1948,6 +1976,8 @@ void IrrDriver::update(float dt)
|
||||
|
||||
m_wind->update();
|
||||
|
||||
PropertyAnimator::get()->update(dt);
|
||||
|
||||
World *world = World::getWorld();
|
||||
|
||||
if (GUIEngine::getCurrentScreen() != NULL &&
|
||||
|
@ -130,13 +130,13 @@ Material* MaterialManager::getDefaultMaterial(video::E_MATERIAL_TYPE shader_type
|
||||
// Try to find a cleaner way
|
||||
// If graphics are disabled, shaders should not be accessed (getShader
|
||||
// asserts that shaders are initialised).
|
||||
if(CVS->isGLSL() && !ProfileWorld::isNoGraphics() &&
|
||||
if(!ProfileWorld::isNoGraphics() && CVS->isGLSL() &&
|
||||
shader_type == Shaders::getShader(ShaderType::ES_OBJECT_UNLIT))
|
||||
default_material->setShaderType(Material::SHADERTYPE_SOLID_UNLIT);
|
||||
else if (CVS->isGLSL() && !ProfileWorld::isNoGraphics() &&
|
||||
else if (!ProfileWorld::isNoGraphics() && CVS->isGLSL() &&
|
||||
shader_type == Shaders::getShader(ShaderType::ES_OBJECTPASS_REF))
|
||||
default_material->setShaderType(Material::SHADERTYPE_ALPHA_TEST);
|
||||
//else if (!ProfileWorld::isNoGraphics() &&
|
||||
//else if (!ProfileWorld::isNoGraphics() && CVS->isGLSL() &&
|
||||
// shader_type == Shaders::getShader(ShaderType::ES_OBJECTPASS))
|
||||
// default_material->setShaderType(Material::SHADERTYPE_ALPHA_BLEND);
|
||||
else
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "graphics/shaders.hpp"
|
||||
#include "graphics/shared_gpu_objects.hpp"
|
||||
#include "graphics/stk_mesh_scene_node.hpp"
|
||||
#include "graphics/weather.hpp"
|
||||
#include "io/file_manager.hpp"
|
||||
#include "karts/abstract_kart.hpp"
|
||||
#include "karts/kart_model.hpp"
|
||||
@ -1638,6 +1639,22 @@ FrameBuffer *PostProcessing::render(scene::ICameraSceneNode * const camnode,
|
||||
}
|
||||
PROFILER_POP_CPU_MARKER();
|
||||
}
|
||||
|
||||
// Handle lightning rendering
|
||||
{
|
||||
PROFILER_PUSH_CPU_MARKER("- Lightning", 0xFF, 0x00, 0x00);
|
||||
ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_LIGHTNING));
|
||||
if (World::getWorld() != NULL)
|
||||
{
|
||||
Weather* m_weather = World::getWorld()->getWeather();
|
||||
|
||||
if (m_weather != NULL && m_weather->shouldLightning())
|
||||
{
|
||||
renderLightning(m_weather->getIntensity());
|
||||
}
|
||||
}
|
||||
PROFILER_POP_CPU_MARKER();
|
||||
}
|
||||
|
||||
// Workaround a bug with srgb fbo on sandy bridge windows
|
||||
if (!CVS->isARBUniformBufferObjectUsable())
|
||||
|
@ -151,7 +151,6 @@ void GL3RenderTarget::draw2DImage(const irr::core::rect<s32>& dest_rect,
|
||||
{
|
||||
irr::core::rect<s32> source_rect(0, 0, m_frame_buffer->getWidth(),
|
||||
m_frame_buffer->getHeight());
|
||||
|
||||
draw2DImageFromRTT(m_texture_id,
|
||||
m_frame_buffer->getWidth(), m_frame_buffer->getHeight(),
|
||||
dest_rect, source_rect,
|
||||
|
@ -66,8 +66,24 @@ GLuint ShaderBase::loadShader(const std::string &file, unsigned type)
|
||||
std::ostringstream code;
|
||||
code << "#version " << CVS->getGLSLVersion()<<"\n";
|
||||
|
||||
// Some drivers report that the compute shaders extension is available,
|
||||
// but they report only OpenGL 3.x version, and thus these extensions
|
||||
// must be enabled manually. Otherwise the shaders compilation will fail
|
||||
// because STK tries to use extensions which are available, but disabled
|
||||
// by default.
|
||||
if (type == GL_COMPUTE_SHADER)
|
||||
{
|
||||
if (CVS->isARBComputeShaderUsable())
|
||||
code << "#extension GL_ARB_compute_shader : enable\n";
|
||||
if (CVS->isARBImageLoadStoreUsable())
|
||||
code << "#extension GL_ARB_shader_image_load_store : enable\n";
|
||||
if (CVS->isARBArraysOfArraysUsable())
|
||||
code << "#extension GL_ARB_arrays_of_arrays : enable\n";
|
||||
}
|
||||
|
||||
if (CVS->isAMDVertexShaderLayerUsable())
|
||||
code << "#extension GL_AMD_vertex_shader_layer : enable\n";
|
||||
|
||||
if (CVS->isAZDOEnabled())
|
||||
{
|
||||
code << "#extension GL_ARB_bindless_texture : enable\n";
|
||||
@ -80,7 +96,7 @@ GLuint ShaderBase::loadShader(const std::string &file, unsigned type)
|
||||
code << "#define VSLayer\n";
|
||||
if (CVS->needsRGBBindlessWorkaround())
|
||||
code << "#define SRGBBindlessFix\n";
|
||||
|
||||
|
||||
//shader compilation fails with some drivers if there is no precision qualifier
|
||||
if (type == GL_FRAGMENT_SHADER)
|
||||
code << "precision mediump float;\n";
|
||||
|
@ -25,8 +25,8 @@
|
||||
#include "graphics/material_manager.hpp"
|
||||
#include "graphics/stk_mesh_scene_node.hpp"
|
||||
#include "io/file_manager.hpp"
|
||||
#include "karts/controller/controller.hpp"
|
||||
#include "karts/abstract_kart.hpp"
|
||||
#include "karts/controller/controller.hpp"
|
||||
#include "karts/kart_properties.hpp"
|
||||
#include "karts/max_speed.hpp"
|
||||
#include "modes/world.hpp"
|
||||
@ -67,11 +67,9 @@ SlipStream::SlipStream(AbstractKart* kart) : MovingTexture(0, 0), m_kart(kart)
|
||||
setTextureMatrix(&(m_node->getMaterial(0).getTextureMatrix(0)));
|
||||
m_slipstream_time = 0.0f;
|
||||
|
||||
float length = m_kart->getKartProperties()->getSlipstreamLength() *
|
||||
m_kart->getPlayerDifficulty()->getSlipstreamLength();
|
||||
float length = m_kart->getKartProperties()->getSlipstreamLength();
|
||||
float kw = m_kart->getKartWidth();
|
||||
float ew = m_kart->getKartProperties()->getSlipstreamWidth() *
|
||||
m_kart->getPlayerDifficulty()->getSlipstreamWidth();
|
||||
float ew = m_kart->getKartProperties()->getSlipstreamWidth();
|
||||
float kl = m_kart->getKartLength();
|
||||
|
||||
Vec3 p[4];
|
||||
@ -314,8 +312,7 @@ void SlipStream::setIntensity(float f, const AbstractKart *kart)
|
||||
bool SlipStream::isSlipstreamReady() const
|
||||
{
|
||||
return m_slipstream_time>
|
||||
m_kart->getKartProperties()->getSlipstreamCollectTime() *
|
||||
m_kart->getPlayerDifficulty()->getSlipstreamCollectTime();
|
||||
m_kart->getKartProperties()->getSlipstreamCollectTime();
|
||||
} // isSlipstreamReady
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -329,16 +326,12 @@ void SlipStream::updateSlipstreamPower()
|
||||
if(m_slipstream_mode==SS_USE)
|
||||
{
|
||||
setIntensity(2.0f, NULL);
|
||||
const KartProperties *kp=m_kart->getKartProperties();
|
||||
const KartProperties *kp = m_kart->getKartProperties();
|
||||
m_kart->increaseMaxSpeed(MaxSpeed::MS_INCREASE_SLIPSTREAM,
|
||||
kp->getSlipstreamMaxSpeedIncrease() *
|
||||
m_kart->getPlayerDifficulty()->getSlipstreamMaxSpeedIncrease(),
|
||||
kp->getSlipstreamAddPower() *
|
||||
m_kart->getPlayerDifficulty()->getSlipstreamAddPower(),
|
||||
kp->getSlipstreamDuration() *
|
||||
m_kart->getPlayerDifficulty()->getSlipstreamDuration(),
|
||||
kp->getSlipstreamFadeOutTime() *
|
||||
m_kart->getPlayerDifficulty()->getSlipstreamFadeOutTime());
|
||||
kp->getSlipstreamMaxSpeedIncrease(),
|
||||
kp->getSlipstreamAddPower(),
|
||||
kp->getSlipstreamDuration(),
|
||||
kp->getSlipstreamFadeOutTime());
|
||||
}
|
||||
} // upateSlipstreamPower
|
||||
|
||||
@ -368,6 +361,8 @@ void SlipStream::setDebugColor(const video::SColor &color)
|
||||
*/
|
||||
void SlipStream::update(float dt)
|
||||
{
|
||||
const KartProperties *kp = m_kart->getKartProperties();
|
||||
|
||||
// Low level AIs should not do any slipstreaming.
|
||||
if(m_kart->getController()->disableSlipstreamBonus())
|
||||
return;
|
||||
@ -394,8 +389,7 @@ void SlipStream::update(float dt)
|
||||
// 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()<m_kart->getKartProperties()->getSlipstreamMinSpeed() *
|
||||
m_kart->getPlayerDifficulty()->getSlipstreamMinSpeed())
|
||||
if(m_kart->getSpeed() < kp->getSlipstreamMinSpeed())
|
||||
{
|
||||
setIntensity(0, NULL);
|
||||
m_slipstream_mode = SS_NONE;
|
||||
@ -436,9 +430,7 @@ void SlipStream::update(float dt)
|
||||
// entirely sure if this makes sense, but it makes it easier to
|
||||
// give karts different slipstream properties.
|
||||
#ifndef DISPLAY_SLIPSTREAM_WITH_0_SPEED_FOR_DEBUGGING
|
||||
if(m_target_kart->getSpeed() <
|
||||
m_kart->getKartProperties()->getSlipstreamMinSpeed() *
|
||||
m_kart->getPlayerDifficulty()->getSlipstreamMinSpeed())
|
||||
if (m_target_kart->getSpeed() < kp->getSlipstreamMinSpeed())
|
||||
{
|
||||
if(UserConfigParams::m_slipstream_debug &&
|
||||
m_kart->getController()->isPlayerController())
|
||||
@ -452,8 +444,7 @@ void SlipStream::update(float dt)
|
||||
// slipstream length+0.5*kart_length()+0.5*target_kart_length
|
||||
// away from the other kart
|
||||
Vec3 delta = m_kart->getXYZ() - m_target_kart->getXYZ();
|
||||
float l = m_kart->getKartProperties()->getSlipstreamLength() *
|
||||
m_kart->getPlayerDifficulty()->getSlipstreamLength()
|
||||
float l = kp->getSlipstreamLength()
|
||||
+ 0.5f*( m_target_kart->getKartLength()
|
||||
+m_kart->getKartLength() );
|
||||
if(delta.length2_2d() > l*l)
|
||||
@ -493,9 +484,7 @@ void SlipStream::update(float dt)
|
||||
{
|
||||
m_slipstream_mode = SS_USE;
|
||||
m_kart->handleZipper();
|
||||
m_slipstream_time =
|
||||
m_kart->getKartProperties()->getSlipstreamCollectTime() *
|
||||
m_kart->getPlayerDifficulty()->getSlipstreamCollectTime();
|
||||
m_slipstream_time = kp->getSlipstreamCollectTime();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -516,8 +505,7 @@ void SlipStream::update(float dt)
|
||||
setIntensity(m_slipstream_time, m_target_kart);
|
||||
|
||||
m_slipstream_mode = SS_COLLECT;
|
||||
if(m_slipstream_time>m_kart->getKartProperties()->getSlipstreamCollectTime() *
|
||||
m_kart->getPlayerDifficulty()->getSlipstreamCollectTime())
|
||||
if (m_slipstream_time > kp->getSlipstreamCollectTime())
|
||||
{
|
||||
setIntensity(1.0f, m_target_kart);
|
||||
}
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include "audio/sfx_manager.hpp"
|
||||
#include "graphics/weather.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "states_screens/race_gui.hpp"
|
||||
#include "utils/random_generator.hpp"
|
||||
|
||||
|
||||
@ -28,11 +27,12 @@
|
||||
|
||||
Weather::Weather(bool lightning, std::string sound)
|
||||
{
|
||||
m_lightning = lightning;
|
||||
m_lightning_enabled = lightning;
|
||||
m_thunder_sound = NULL;
|
||||
m_weather_sound = NULL;
|
||||
m_lightning = 0.0f;
|
||||
|
||||
if (m_lightning)
|
||||
if (m_lightning_enabled)
|
||||
{
|
||||
m_thunder_sound = SFXManager::get()->createSoundSource("thunder");
|
||||
}
|
||||
@ -61,27 +61,30 @@ Weather::~Weather()
|
||||
|
||||
void Weather::update(float dt)
|
||||
{
|
||||
if (m_lightning)
|
||||
if (!m_lightning_enabled)
|
||||
return;
|
||||
|
||||
if (World::getWorld()->getRaceGUI() == NULL)
|
||||
return;
|
||||
|
||||
m_next_lightning -= dt;
|
||||
|
||||
if (m_next_lightning < 0.0f)
|
||||
{
|
||||
m_next_lightning -= dt;
|
||||
|
||||
if (m_next_lightning < 0.0f)
|
||||
startLightning();
|
||||
|
||||
if (m_thunder_sound)
|
||||
{
|
||||
RaceGUIBase* gui_base = World::getWorld()->getRaceGUI();
|
||||
|
||||
if (gui_base != NULL)
|
||||
{
|
||||
gui_base->doLightning();
|
||||
|
||||
if (m_thunder_sound)
|
||||
{
|
||||
m_thunder_sound->play();
|
||||
}
|
||||
}
|
||||
|
||||
RandomGenerator g;
|
||||
m_next_lightning = 35 + (float)g.get(35);
|
||||
m_thunder_sound->play();
|
||||
}
|
||||
|
||||
RandomGenerator g;
|
||||
m_next_lightning = 35 + (float)g.get(35);
|
||||
}
|
||||
|
||||
if (m_lightning > 0.0f)
|
||||
{
|
||||
m_lightning -= dt;
|
||||
}
|
||||
} // update
|
||||
|
||||
@ -95,3 +98,12 @@ void Weather::playSound()
|
||||
m_weather_sound->play();
|
||||
}
|
||||
}
|
||||
|
||||
irr::core::vector3df Weather::getIntensity()
|
||||
{
|
||||
irr::core::vector3df value = {0.7f * m_lightning,
|
||||
0.7f * m_lightning,
|
||||
0.7f * std::min(1.0f, m_lightning * 1.5f)};
|
||||
|
||||
return value;
|
||||
}
|
||||
|
@ -19,12 +19,15 @@
|
||||
#ifndef HEADER_WEATHER_HPP
|
||||
#define HEADER_WEATHER_HPP
|
||||
|
||||
#include <vector3d.h>
|
||||
|
||||
class SFXBase;
|
||||
|
||||
class Weather
|
||||
{
|
||||
bool m_lightning;
|
||||
bool m_lightning_enabled;
|
||||
float m_next_lightning;
|
||||
float m_lightning;
|
||||
|
||||
SFXBase* m_thunder_sound;
|
||||
SFXBase* m_weather_sound;
|
||||
@ -35,6 +38,12 @@ public:
|
||||
|
||||
void update(float dt);
|
||||
void playSound();
|
||||
|
||||
/** Set the flag that a lightning should be shown. */
|
||||
void startLightning() { m_lightning = 1.0f; }
|
||||
bool shouldLightning() { return m_lightning > 0.0f; }
|
||||
|
||||
irr::core::vector3df getIntensity();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "guiengine/engine.hpp"
|
||||
#include "guiengine/skin.hpp"
|
||||
#include "io/file_manager.hpp"
|
||||
#include "utils/string_utils.hpp"
|
||||
#include "utils/translation.hpp"
|
||||
|
||||
#include <clocale>
|
||||
@ -62,7 +63,8 @@ ScalableFont::ScalableFont(IGUIEnvironment *env, TTFLoadingType type)
|
||||
// don't grab environment, to avoid circular references
|
||||
m_video_driver = m_gui_env->getVideoDriver();
|
||||
|
||||
m_spritebank = m_gui_env->addEmptySpriteBank((std::to_string(type)).c_str());
|
||||
m_spritebank = m_gui_env->addEmptySpriteBank(
|
||||
(StringUtils::toString(type)).c_str());
|
||||
if (m_spritebank)
|
||||
m_spritebank->grab();
|
||||
}
|
||||
@ -489,6 +491,7 @@ std::set<wchar_t> ScalableFont::getPreloadCharacters(const GUIEngine::TTFLoading
|
||||
preload_char.insert((wchar_t)i); //Include basic Latin too, starting from A (char code 65)
|
||||
|
||||
setlocale(LC_ALL, "en_US.UTF8");
|
||||
std::set<wchar_t> upper;
|
||||
std::set<wchar_t>::iterator it = preload_char.begin();
|
||||
|
||||
while (it != preload_char.end())
|
||||
@ -496,7 +499,15 @@ std::set<wchar_t> ScalableFont::getPreloadCharacters(const GUIEngine::TTFLoading
|
||||
//Only use all capital letter for bold char with latin (<640 of char code).
|
||||
//Remove all characters (>char code 8191) not used by the title
|
||||
if (((iswlower((wchar_t)*it) || !iswalpha((wchar_t)*it)) && *it < 640) || *it > 8191)
|
||||
{
|
||||
if (*it < 8192 && iswalpha((wchar_t)*it))
|
||||
{
|
||||
//Make sure we include all upper case letters,
|
||||
//because the title font shows all characters as capital letters
|
||||
upper.insert(towupper((wchar_t)*it));
|
||||
}
|
||||
it = preload_char.erase(it);
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
@ -505,6 +516,7 @@ std::set<wchar_t> ScalableFont::getPreloadCharacters(const GUIEngine::TTFLoading
|
||||
for (u32 i = 32; i < 65; ++i)
|
||||
preload_char.insert((wchar_t)i); //Include basic symbol (from space (char code 32) to @(char code 64))
|
||||
|
||||
preload_char.insert(upper.begin(), upper.end());
|
||||
preload_char.insert((wchar_t)160); //Non-breaking space
|
||||
|
||||
//Remove Ordinal indicator (char code 170 and 186)
|
||||
@ -824,7 +836,7 @@ void ScalableFont::doDraw(const core::stringw& text,
|
||||
[GUIEngine::getFont()->getSpriteNoFromChar(&c)].Frames[0].textureNumber
|
||||
== m_spritebank->getTextureCount() - 1) //Prevent overwriting texture used by billboard text
|
||||
{
|
||||
Log::debug("ScalableFont::doDraw",
|
||||
Log::debug("ScalableFont::doDraw",
|
||||
"Character used by billboard text is in the last "
|
||||
"glyph page of normal font. Create a new glyph "
|
||||
"page for new characters inserted later to prevent "
|
||||
@ -1000,12 +1012,12 @@ void ScalableFont::doDraw(const core::stringw& text,
|
||||
|
||||
if (fallback[n] || m_type == T_BOLD)
|
||||
{
|
||||
video::SColor title_colors[] = {GUIEngine::getSkin()->getColor("font::top" ),
|
||||
GUIEngine::getSkin()->getColor("font::bottom"),
|
||||
GUIEngine::getSkin()->getColor("font::top" ),
|
||||
GUIEngine::getSkin()->getColor("font::bottom")
|
||||
};
|
||||
video::SColor top = GUIEngine::getSkin()->getColor("font::top");
|
||||
video::SColor bottom = GUIEngine::getSkin()->getColor("font::bottom");
|
||||
top.setAlpha(color.getAlpha());
|
||||
bottom.setAlpha(color.getAlpha());
|
||||
|
||||
video::SColor title_colors[] = {top, bottom, top, bottom};
|
||||
if (charCollector != NULL)
|
||||
{
|
||||
charCollector->collectChar(texture,
|
||||
|
@ -1959,12 +1959,6 @@ void Skin::process3DPane(IGUIElement *element, const core::recti &rect,
|
||||
{
|
||||
ModelViewWidget* mvw = dynamic_cast<ModelViewWidget*>(widget);
|
||||
mvw->drawRTTScene(rect);
|
||||
/*FrameBuffer* fb = mvw->getFrameBuffer();
|
||||
if (fb != NULL && fb->getRTT().size() > 0)
|
||||
{
|
||||
draw2DImageFromRTT(fb->getRTT()[0], 512, 512,
|
||||
rect, core::rect<s32>(0, 0, 512, 512), NULL, SColor(255, 255, 255, 255), true);
|
||||
}*/
|
||||
}
|
||||
else if (type == WTYPE_ICON_BUTTON || type == WTYPE_MODEL_VIEW)
|
||||
{
|
||||
|
@ -24,8 +24,18 @@
|
||||
double click/ctrl click: word select + drag to select whole words, triple click to select line
|
||||
optional? dragging selected text
|
||||
numerical
|
||||
correct the mark position in RTL text, currently you can identify by highlight the text
|
||||
*/
|
||||
|
||||
#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_)
|
||||
#define UTF16_IS_SURROGATE_LO(c) (((c) & 0xFC00) == 0xDC00)
|
||||
#define UTF16_IS_SURROGATE_HI(c) (((c) & 0xFC00) == 0xD800)
|
||||
|
||||
namespace irr
|
||||
{
|
||||
void updateICPos(void* hWnd, s32 x, s32 y, s32 height);
|
||||
}
|
||||
#endif
|
||||
|
||||
StkTime::TimeType getTime()
|
||||
{
|
||||
@ -44,7 +54,11 @@ CGUIEditBox::CGUIEditBox(const wchar_t* text, bool border,
|
||||
PasswordChar(L'*'), HAlign(EGUIA_UPPERLEFT), VAlign(EGUIA_CENTER),
|
||||
CurrentTextRect(0,0,1,1), FrameRect(rectangle)
|
||||
{
|
||||
m_rtl = is_rtl;
|
||||
//m_rtl = is_rtl;
|
||||
m_rtl = false;
|
||||
// FIXME quick hack to enable mark movement with keyboard and mouse for rtl language,
|
||||
// don't know why it's disabled in the first place, because STK fail
|
||||
// to input unicode characters before?
|
||||
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CGUIEditBox");
|
||||
@ -229,6 +243,12 @@ bool CGUIEditBox::OnEvent(const SEvent& event)
|
||||
}
|
||||
}
|
||||
break;
|
||||
#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_)
|
||||
case EET_IMPUT_METHOD_EVENT:
|
||||
if (processIMEEvent(event))
|
||||
return true;
|
||||
break;
|
||||
#endif
|
||||
case EET_KEY_INPUT_EVENT:
|
||||
if (processKey(event))
|
||||
return true;
|
||||
@ -282,7 +302,11 @@ bool CGUIEditBox::processKey(const SEvent& event)
|
||||
|
||||
core::stringw s;
|
||||
s = Text.subString(realmbgn, realmend - realmbgn).c_str();
|
||||
#ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_
|
||||
Operator->copyToClipboard(s.c_str());
|
||||
#else
|
||||
Operator->copyToClipboard(StringUtils::wideToUtf8(s).c_str());
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case KEY_KEY_X:
|
||||
@ -295,7 +319,11 @@ bool CGUIEditBox::processKey(const SEvent& event)
|
||||
// copy
|
||||
core::stringw sc;
|
||||
sc = Text.subString(realmbgn, realmend - realmbgn).c_str();
|
||||
#ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_
|
||||
Operator->copyToClipboard(sc.c_str());
|
||||
#else
|
||||
Operator->copyToClipboard(StringUtils::wideToUtf8(sc).c_str());
|
||||
#endif
|
||||
|
||||
if (isEnabled())
|
||||
{
|
||||
@ -324,20 +352,32 @@ bool CGUIEditBox::processKey(const SEvent& event)
|
||||
const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin;
|
||||
|
||||
// add new character
|
||||
#ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_
|
||||
const wchar_t* p = Operator->getTextFromClipboard();
|
||||
#else
|
||||
const c8* p = Operator->getTextFromClipboard();
|
||||
#endif
|
||||
if (p)
|
||||
{
|
||||
if (MarkBegin == MarkEnd)
|
||||
{
|
||||
// insert text
|
||||
core::stringw s = Text.subString(0, CursorPos);
|
||||
#ifndef _IRR_COMPILE_WITH_WINDOWS_DEVICE_
|
||||
s.append(StringUtils::utf8ToWide(p));
|
||||
#else
|
||||
s.append(p);
|
||||
#endif
|
||||
s.append( Text.subString(CursorPos, Text.size()-CursorPos) );
|
||||
|
||||
if (!Max || s.size()<=Max) // thx to Fish FH for fix
|
||||
{
|
||||
Text = s;
|
||||
#ifndef _IRR_COMPILE_WITH_WINDOWS_DEVICE_
|
||||
s = StringUtils::utf8ToWide(p);
|
||||
#else
|
||||
s = p;
|
||||
#endif
|
||||
CursorPos += s.size();
|
||||
}
|
||||
}
|
||||
@ -346,13 +386,22 @@ bool CGUIEditBox::processKey(const SEvent& event)
|
||||
// replace text
|
||||
|
||||
core::stringw s = Text.subString(0, realmbgn);
|
||||
|
||||
#ifndef _IRR_COMPILE_WITH_WINDOWS_DEVICE_
|
||||
s.append(StringUtils::utf8ToWide(p));
|
||||
#else
|
||||
s.append(p);
|
||||
#endif
|
||||
s.append( Text.subString(realmend, Text.size()-realmend) );
|
||||
|
||||
if (!Max || s.size()<=Max) // thx to Fish FH for fix
|
||||
{
|
||||
Text = s;
|
||||
#ifndef _IRR_COMPILE_WITH_WINDOWS_DEVICE_
|
||||
s = StringUtils::utf8ToWide(p);
|
||||
#else
|
||||
s = p;
|
||||
#endif
|
||||
CursorPos = realmbgn + s.size();
|
||||
}
|
||||
}
|
||||
@ -734,10 +783,102 @@ bool CGUIEditBox::processKey(const SEvent& event)
|
||||
|
||||
calculateScrollPos();
|
||||
|
||||
#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_)
|
||||
switch(event.KeyInput.Key)
|
||||
{
|
||||
// If cursor points the surrogate low, send KEY_LEFT event.
|
||||
case KEY_UP:
|
||||
case KEY_DOWN:
|
||||
if (MultiLine || (WordWrap && BrokenText.size() > 1) )
|
||||
{
|
||||
if (UTF16_IS_SURROGATE_LO(Text[CursorPos]))
|
||||
{
|
||||
SEvent leftEvent;
|
||||
leftEvent = event;
|
||||
leftEvent.KeyInput.Key = KEY_LEFT;
|
||||
Environment->postEventFromUser(leftEvent);
|
||||
}
|
||||
}
|
||||
break;
|
||||
// If cursor points the surrogate low, send a same event.
|
||||
case KEY_LEFT:
|
||||
case KEY_RIGHT:
|
||||
case KEY_DELETE:
|
||||
if (UTF16_IS_SURROGATE_LO(Text[CursorPos]))
|
||||
Environment->postEventFromUser(event);
|
||||
break;
|
||||
// If cursor points front of the surrogate high, send a same event.
|
||||
case KEY_BACK:
|
||||
if (CursorPos > 0)
|
||||
{
|
||||
if (UTF16_IS_SURROGATE_HI(Text[CursorPos-1]))
|
||||
Environment->postEventFromUser(event);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_)
|
||||
bool CGUIEditBox::processIMEEvent(const SEvent& event)
|
||||
{
|
||||
switch(event.InputMethodEvent.Event)
|
||||
{
|
||||
case EIME_CHAR_INPUT:
|
||||
inputChar(event.InputMethodEvent.Char);
|
||||
return true;
|
||||
case EIME_CHANGE_POS:
|
||||
{
|
||||
core::position2di pos = calculateICPos();
|
||||
|
||||
IGUIFont* font = OverrideFont;
|
||||
IGUISkin* skin = Environment->getSkin();
|
||||
|
||||
if (!OverrideFont)
|
||||
font = skin->getFont();
|
||||
|
||||
irr::updateICPos(event.InputMethodEvent.Handle, pos.X,pos.Y, font->getDimension(L"|").Height);
|
||||
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//! calculate the position of input composition window
|
||||
core::position2di CGUIEditBox::calculateICPos()
|
||||
{
|
||||
core::position2di pos;
|
||||
IGUIFont* font = OverrideFont;
|
||||
IGUISkin* skin = Environment->getSkin();
|
||||
if (!OverrideFont)
|
||||
font = skin->getFont();
|
||||
|
||||
//drop the text that clipping on the right side
|
||||
if (WordWrap | MultiLine)
|
||||
{
|
||||
// todo : It looks like a heavy drinker. Strange!!
|
||||
pos.X = CurrentTextRect.LowerRightCorner.X - font->getDimension(Text.subString(CursorPos, BrokenTextPositions[getLineFromPos(CursorPos)] + BrokenText[getLineFromPos(CursorPos)].size() - CursorPos).c_str()).Width;
|
||||
pos.Y = CurrentTextRect.UpperLeftCorner.Y + font->getDimension(L"|").Height + (Border ? 3 : 0) - ((MultiLine | WordWrap) ? 3 : 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
pos.X = CurrentTextRect.LowerRightCorner.X - font->getDimension(Text.subString(CursorPos, Text.size() - CursorPos).c_str()).Width;
|
||||
pos.Y = AbsoluteRect.getCenter().Y + (Border ? 3 : 0); //bug? The text is always drawn in the height of the center. SetTextAlignment() doesn't influence.
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
//! draws the element and its children
|
||||
void CGUIEditBox::draw()
|
||||
{
|
||||
@ -849,20 +990,12 @@ void CGUIEditBox::draw()
|
||||
startPos = ml ? BrokenTextPositions[i] : 0;
|
||||
}
|
||||
|
||||
|
||||
if (m_rtl)
|
||||
{
|
||||
font->draw(translations->fribidize(txtLine->c_str()), CurrentTextRect,
|
||||
OverrideColorEnabled ? OverrideColor : skin->getColor(EGDC_BUTTON_TEXT),
|
||||
false, true, &localClipRect);
|
||||
}
|
||||
else
|
||||
{
|
||||
// draw normal text
|
||||
font->draw(txtLine->c_str(), CurrentTextRect,
|
||||
OverrideColorEnabled ? OverrideColor : skin->getColor(EGDC_BUTTON_TEXT),
|
||||
false, true, &localClipRect);
|
||||
}
|
||||
font->draw(translations->fribidize(txtLine->c_str()), CurrentTextRect,
|
||||
OverrideColorEnabled ? OverrideColor : skin->getColor(EGDC_BUTTON_TEXT),
|
||||
false, true, &localClipRect);
|
||||
// draw with fribidize no matter what language, because in fribidize function,
|
||||
// it will return the input pointer if (this->isRTLLanguage()) from Translations::isRTLText
|
||||
// is false
|
||||
|
||||
// draw mark and marked text
|
||||
if (focus && MarkBegin != MarkEnd && i >= hlineStart && i < hlineStart + hlineCount)
|
||||
@ -1028,6 +1161,13 @@ bool CGUIEditBox::processMouse(const SEvent& event)
|
||||
if (Environment->hasFocus(this) && !m_rtl)
|
||||
{
|
||||
CursorPos = getCursorPos(event.MouseInput.X, event.MouseInput.Y);
|
||||
#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_)
|
||||
if (UTF16_IS_SURROGATE_LO(Text[CursorPos]))
|
||||
{
|
||||
if (CursorPos > 0)
|
||||
--CursorPos;
|
||||
}
|
||||
#endif
|
||||
if (MouseMarking)
|
||||
{
|
||||
setTextMarkers( MarkBegin, CursorPos );
|
||||
@ -1042,6 +1182,13 @@ bool CGUIEditBox::processMouse(const SEvent& event)
|
||||
if (MouseMarking)
|
||||
{
|
||||
CursorPos = getCursorPos(event.MouseInput.X, event.MouseInput.Y);
|
||||
#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_)
|
||||
if (UTF16_IS_SURROGATE_LO(Text[CursorPos]))
|
||||
{
|
||||
if (CursorPos > 0)
|
||||
--CursorPos;
|
||||
}
|
||||
#endif
|
||||
setTextMarkers( MarkBegin, CursorPos );
|
||||
calculateScrollPos();
|
||||
return true;
|
||||
@ -1054,6 +1201,13 @@ bool CGUIEditBox::processMouse(const SEvent& event)
|
||||
BlinkStartTime = getTime();
|
||||
MouseMarking = true;
|
||||
CursorPos = getCursorPos(event.MouseInput.X, event.MouseInput.Y);
|
||||
#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_)
|
||||
if (UTF16_IS_SURROGATE_LO(Text[CursorPos]))
|
||||
{
|
||||
if (CursorPos > 0)
|
||||
--CursorPos;
|
||||
}
|
||||
#endif
|
||||
setTextMarkers(CursorPos, CursorPos );
|
||||
calculateScrollPos();
|
||||
return true;
|
||||
@ -1070,6 +1224,13 @@ bool CGUIEditBox::processMouse(const SEvent& event)
|
||||
// move cursor
|
||||
CursorPos = getCursorPos(event.MouseInput.X, event.MouseInput.Y);
|
||||
|
||||
#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_)
|
||||
if (UTF16_IS_SURROGATE_LO(Text[CursorPos]))
|
||||
{
|
||||
if (CursorPos > 0)
|
||||
--CursorPos;
|
||||
}
|
||||
#endif
|
||||
s32 newMarkBegin = MarkBegin;
|
||||
if (!MouseMarking)
|
||||
newMarkBegin = CursorPos;
|
||||
|
@ -137,6 +137,11 @@ using namespace gui;
|
||||
|
||||
bool processKey(const SEvent& event);
|
||||
bool processMouse(const SEvent& event);
|
||||
#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_)
|
||||
bool processIMEEvent(const SEvent& event);
|
||||
//! calculates the input composition position
|
||||
core::position2di calculateICPos();
|
||||
#endif
|
||||
s32 getCursorPos(s32 x, s32 y);
|
||||
|
||||
bool MouseMarking;
|
||||
|
@ -46,6 +46,8 @@ DynamicRibbonWidget::DynamicRibbonWidget(const bool combo, const bool multi_row)
|
||||
m_supports_multiplayer = true;
|
||||
m_scrolling_enabled = true;
|
||||
m_animated_contents = false;
|
||||
// Don't initialize m_font here to make lazy loading characters work
|
||||
m_font = NULL;
|
||||
|
||||
// by default, set all players to have no selection in this ribbon
|
||||
for (unsigned int n=0; n<MAX_PLAYER_COUNT; n++)
|
||||
@ -730,6 +732,16 @@ void DynamicRibbonWidget::onRibbonWidgetScroll(const int delta_x)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void DynamicRibbonWidget::setText(const wchar_t *text)
|
||||
{
|
||||
Widget::setText(text);
|
||||
|
||||
if (m_label != NULL)
|
||||
m_label->setText(text);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void DynamicRibbonWidget::onRibbonWidgetFocus(RibbonWidget* emitter, const int playerID)
|
||||
{
|
||||
if (m_deactivated) return;
|
||||
|
@ -302,6 +302,8 @@ namespace GUIEngine
|
||||
/** \brief callback from IRibbonListener */
|
||||
virtual void onSelectionChange(){}
|
||||
|
||||
virtual void setText(const wchar_t *text);
|
||||
|
||||
virtual void update(float delta);
|
||||
|
||||
/** Set approximately how many items are expected to be in this ribbon; will help the layout
|
||||
|
@ -15,21 +15,19 @@
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#include "config/user_config.hpp"
|
||||
#include "guiengine/engine.hpp"
|
||||
#include "guiengine/widgets/kart_stats_widget.hpp"
|
||||
#include "utils/string_utils.hpp"
|
||||
#include <string.h>
|
||||
#include "karts/abstract_characteristic.hpp"
|
||||
#include "karts/kart_properties.hpp"
|
||||
#include "karts/kart_properties_manager.hpp"
|
||||
|
||||
#include "utils/log.hpp"
|
||||
#include "utils/string_utils.hpp"
|
||||
|
||||
#include "config/user_config.hpp"
|
||||
|
||||
#include <IGUIEnvironment.h>
|
||||
#include <IGUIElement.h>
|
||||
#include <IGUIButton.h>
|
||||
#include <string>
|
||||
|
||||
using namespace GUIEngine;
|
||||
using namespace irr::core;
|
||||
@ -41,6 +39,7 @@ KartStatsWidget::KartStatsWidget(core::recti area, const int player_id,
|
||||
std::string kart_group, bool multiplayer,
|
||||
bool display_text) : Widget(WTYPE_DIV)
|
||||
{
|
||||
m_title_font = !multiplayer;
|
||||
m_player_id = player_id;
|
||||
|
||||
const std::string default_kart = UserConfigParams::m_default_kart;
|
||||
@ -81,15 +80,21 @@ KartStatsWidget::KartStatsWidget(core::recti area, const int player_id,
|
||||
m_children.push_back(skill_bar);
|
||||
}
|
||||
|
||||
m_skills[SKILL_MASS]->setValue((int)(props->getMass()/5));
|
||||
// Scale the values so they look better
|
||||
// The scaling factor and offset were found by trial and error.
|
||||
// It should look nice and you should be able to see the difference between
|
||||
// different masses or velocities.
|
||||
m_skills[SKILL_MASS]->setValue((int)
|
||||
((props->getCombinedCharacteristic()->getMass() - 20) / 4));
|
||||
m_skills[SKILL_MASS]->setLabel(_("WEIGHT"));
|
||||
m_skills[SKILL_MASS]->m_properties[PROP_ID] = StringUtils::insertValues("@p%i_mass", m_player_id);
|
||||
|
||||
m_skills[SKILL_SPEED]->setValue((int)((props->getAbsMaxSpeed()-20)*9));
|
||||
m_skills[SKILL_SPEED]->setValue((int)
|
||||
((props->getCombinedCharacteristic()->getEngineMaxSpeed() - 15) * 6));
|
||||
m_skills[SKILL_SPEED]->setLabel(_("SPEED"));
|
||||
m_skills[SKILL_SPEED]->m_properties[PROP_ID] = StringUtils::insertValues("@p%i_speed", m_player_id);
|
||||
|
||||
m_skills[SKILL_POWER]->setValue((int)(props->getAvgPower()));
|
||||
m_skills[SKILL_POWER]->setValue((int) ((props->getAvgPower() - 30) / 20));
|
||||
m_skills[SKILL_POWER]->setLabel(_("POWER"));
|
||||
m_skills[SKILL_POWER]->m_properties[PROP_ID] = StringUtils::insertValues("@p%i_power", m_player_id);
|
||||
|
||||
@ -149,7 +154,7 @@ void KartStatsWidget::setSize(const int x, const int y, const int w, const int h
|
||||
|
||||
// -- sizes
|
||||
m_skill_bar_w = w;
|
||||
m_skill_bar_h = GUIEngine::getTitleFontHeight();
|
||||
m_skill_bar_h = (m_title_font ? GUIEngine::getTitleFontHeight() : GUIEngine::getFontHeight());
|
||||
|
||||
// for shrinking effect
|
||||
if (h < 175)
|
||||
|
@ -310,6 +310,8 @@ void ModelViewWidget::clearRttProvider()
|
||||
|
||||
void ModelViewWidget::drawRTTScene(const irr::core::rect<s32>& dest_rect) const
|
||||
{
|
||||
glEnable(GL_FRAMEBUFFER_SRGB);
|
||||
m_render_target->draw2DImage(dest_rect, NULL, video::SColor(255, 255, 255, 255), true);
|
||||
glDisable(GL_FRAMEBUFFER_SRGB);
|
||||
}
|
||||
|
||||
|
@ -52,6 +52,7 @@ namespace irr {
|
||||
# include <dirent.h>
|
||||
# include <unistd.h>
|
||||
#else
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <direct.h>
|
||||
# include <windows.h>
|
||||
# include <stdio.h>
|
||||
|
@ -225,6 +225,7 @@ void Attachment::clear()
|
||||
*/
|
||||
void Attachment::hitBanana(Item *item, int new_attachment)
|
||||
{
|
||||
const KartProperties *kp = m_kart->getKartProperties();
|
||||
const StateManager::ActivePlayer *const ap = m_kart->getController()
|
||||
->getPlayer();
|
||||
if(ap && ap->getConstProfile()==PlayerManager::getCurrentPlayer())
|
||||
@ -266,9 +267,7 @@ void Attachment::hitBanana(Item *item, int new_attachment)
|
||||
// default time. This is necessary to avoid that a kart lands on the
|
||||
// same banana again once the explosion animation is finished, giving
|
||||
// the kart the same penalty twice.
|
||||
float f = std::max(item->getDisableTime(),
|
||||
m_kart->getKartProperties()->getExplosionTime() *
|
||||
m_kart->getPlayerDifficulty()->getExplosionTime() + 2.0f);
|
||||
float f = std::max(item->getDisableTime(), kp->getExplosionDuration() + 2.0f);
|
||||
item->setDisableTime(f);
|
||||
break;
|
||||
}
|
||||
@ -296,7 +295,7 @@ void Attachment::hitBanana(Item *item, int new_attachment)
|
||||
switch (new_attachment)
|
||||
{
|
||||
case 0:
|
||||
set( ATTACH_PARACHUTE,stk_config->m_parachute_time+leftover_time);
|
||||
set(ATTACH_PARACHUTE, kp->getParachuteDuration() + leftover_time);
|
||||
m_initial_speed = m_kart->getSpeed();
|
||||
|
||||
// if going very slowly or backwards,
|
||||
@ -310,12 +309,12 @@ void Attachment::hitBanana(Item *item, int new_attachment)
|
||||
// sound -> playSfx ( SOUND_SHOOMF ) ;
|
||||
break ;
|
||||
case 2:
|
||||
set( ATTACH_ANVIL, stk_config->m_anvil_time+leftover_time);
|
||||
set(ATTACH_ANVIL, kp->getAnvilDuration() + leftover_time);
|
||||
// if ( m_kart == m_kart[0] )
|
||||
// sound -> playSfx ( SOUND_SHOOMF ) ;
|
||||
// Reduce speed once (see description above), all other changes are
|
||||
// handled in Kart::updatePhysics
|
||||
m_kart->adjustSpeed(stk_config->m_anvil_speed_factor);
|
||||
m_kart->adjustSpeed(kp->getAnvilSpeedFactor());
|
||||
m_kart->updateWeight();
|
||||
break ;
|
||||
} // switch
|
||||
@ -420,12 +419,14 @@ void Attachment::update(float dt)
|
||||
// This percentage is based on the ratio of
|
||||
// initial_speed / initial_max_speed
|
||||
|
||||
float f = m_initial_speed / stk_config->m_parachute_max_speed;
|
||||
const KartProperties *kp = m_kart->getKartProperties();
|
||||
|
||||
float f = m_initial_speed / kp->getParachuteMaxSpeed();
|
||||
if (f > 1.0f) f = 1.0f; // cap fraction
|
||||
if (m_kart->getSpeed() <= m_initial_speed *
|
||||
(stk_config->m_parachute_lbound_fraction +
|
||||
f * ( stk_config->m_parachute_ubound_fraction
|
||||
- stk_config->m_parachute_lbound_fraction)))
|
||||
(kp->getParachuteLboundFraction() +
|
||||
f * (kp->getParachuteUboundFraction()
|
||||
- kp->getParachuteLboundFraction())))
|
||||
{
|
||||
m_time_left = -1;
|
||||
}
|
||||
@ -507,6 +508,12 @@ void Attachment::update(float dt)
|
||||
clear();
|
||||
} // update
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
float Attachment::weightAdjust() const
|
||||
{
|
||||
return m_type == ATTACH_ANVIL ? m_kart->getKartProperties()->getAnvilWeight() : 0.0f;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Inform any eventual plugin when an animation is done. */
|
||||
void Attachment::OnAnimationEnd(scene::IAnimatedMeshSceneNode* node)
|
||||
|
@ -130,8 +130,7 @@ public:
|
||||
AbstractKart* getPreviousOwner() const { return m_previous_owner; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns additional weight for the kart. */
|
||||
float weightAdjust() const {
|
||||
return m_type==ATTACH_ANVIL ? stk_config->m_anvil_weight : 0.0f; }
|
||||
float weightAdjust() const;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Return the currently associated scene node (used by e.g the swatter) */
|
||||
scene::IAnimatedMeshSceneNode* getNode() {return m_node;}
|
||||
|
@ -176,8 +176,7 @@ bool Plunger::hit(AbstractKart *kart, PhysicalObject *obj)
|
||||
}
|
||||
else
|
||||
{
|
||||
m_keep_alive = m_owner->getKartProperties()->getRubberBandDuration() *
|
||||
m_owner->getPlayerDifficulty()->getRubberBandDuration();
|
||||
m_keep_alive = m_owner->getKartProperties()->getPlungerBandDuration();
|
||||
|
||||
// Make this object invisible by placing it faaar down. Not that if this
|
||||
// objects is simply removed from the scene graph, it might be auto-deleted
|
||||
|
@ -171,6 +171,8 @@ void Powerup::adjustSound()
|
||||
*/
|
||||
void Powerup::use()
|
||||
{
|
||||
const KartProperties *kp = m_owner->getKartProperties();
|
||||
|
||||
// The player gets an achievement point for using a powerup
|
||||
StateManager::ActivePlayer * player = m_owner->getController()->getPlayer();
|
||||
if (m_type != PowerupManager::POWERUP_NOTHING &&
|
||||
@ -221,9 +223,7 @@ void Powerup::use()
|
||||
|
||||
case PowerupManager::POWERUP_SWATTER:
|
||||
m_owner->getAttachment()
|
||||
->set(Attachment::ATTACH_SWATTER,
|
||||
m_owner->getKartProperties()->getSwatterDuration() *
|
||||
m_owner->getPlayerDifficulty()->getSwatterDuration());
|
||||
->set(Attachment::ATTACH_SWATTER, kp->getSwatterDuration());
|
||||
break;
|
||||
|
||||
case PowerupManager::POWERUP_BUBBLEGUM:
|
||||
@ -258,12 +258,12 @@ void Powerup::use()
|
||||
if (m_owner->getIdent() == "nolok")
|
||||
{
|
||||
m_owner->getAttachment()->set(Attachment::ATTACH_NOLOK_BUBBLEGUM_SHIELD,
|
||||
stk_config->m_bubblegum_shield_time);
|
||||
kp->getBubblegumShieldDuration());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_owner->getAttachment()->set(Attachment::ATTACH_BUBBLEGUM_SHIELD,
|
||||
stk_config->m_bubblegum_shield_time);
|
||||
kp->getBubblegumShieldDuration());
|
||||
}
|
||||
}
|
||||
else // using a bubble gum while still having a shield
|
||||
@ -271,12 +271,12 @@ void Powerup::use()
|
||||
if (m_owner->getIdent() == "nolok")
|
||||
{
|
||||
m_owner->getAttachment()->set(Attachment::ATTACH_NOLOK_BUBBLEGUM_SHIELD,
|
||||
stk_config->m_bubblegum_shield_time + m_owner->getShieldTime());
|
||||
kp->getBubblegumShieldDuration() + m_owner->getShieldTime());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_owner->getAttachment()->set(Attachment::ATTACH_BUBBLEGUM_SHIELD,
|
||||
stk_config->m_bubblegum_shield_time + m_owner->getShieldTime());
|
||||
kp->getBubblegumShieldDuration() + m_owner->getShieldTime());
|
||||
}
|
||||
}
|
||||
|
||||
@ -300,9 +300,9 @@ void Powerup::use()
|
||||
if(kart->getPosition() == 1)
|
||||
{
|
||||
kart->getAttachment()->set(Attachment::ATTACH_ANVIL,
|
||||
stk_config->m_anvil_time);
|
||||
kp->getAnvilDuration());
|
||||
kart->updateWeight();
|
||||
kart->adjustSpeed(stk_config->m_anvil_speed_factor*0.5f);
|
||||
kart->adjustSpeed(kp->getAnvilSpeedFactor() * 0.5f);
|
||||
|
||||
// should we position the sound at the kart that is hit,
|
||||
// or the kart "throwing" the anvil? Ideally it should be both.
|
||||
@ -337,9 +337,8 @@ void Powerup::use()
|
||||
}
|
||||
if(m_owner->getPosition() > kart->getPosition())
|
||||
{
|
||||
kart->getAttachment()
|
||||
->set(Attachment::ATTACH_PARACHUTE,
|
||||
stk_config->m_parachute_time_other);
|
||||
kart->getAttachment()->set(Attachment::ATTACH_PARACHUTE,
|
||||
kp->getParachuteDurationOther());
|
||||
|
||||
if(kart->getController()->isPlayerController())
|
||||
player_kart = kart;
|
||||
|
@ -134,6 +134,8 @@ void RubberBand::updatePosition()
|
||||
*/
|
||||
void RubberBand::update(float dt)
|
||||
{
|
||||
const KartProperties *kp = m_owner->getKartProperties();
|
||||
|
||||
if(m_owner->isEliminated())
|
||||
{
|
||||
// Rubber band snaps
|
||||
@ -149,8 +151,7 @@ void RubberBand::update(float dt)
|
||||
// Check for rubber band snapping
|
||||
// ------------------------------
|
||||
float l = (m_end_position-k).length2();
|
||||
float max_len = m_owner->getKartProperties()->getRubberBandMaxLength() *
|
||||
m_owner->getPlayerDifficulty()->getRubberBandMaxLength();
|
||||
float max_len = kp->getPlungerBandMaxLength();
|
||||
if(l>max_len*max_len)
|
||||
{
|
||||
// Rubber band snaps
|
||||
@ -163,8 +164,7 @@ void RubberBand::update(float dt)
|
||||
// ----------------------------
|
||||
if(m_attached_state!=RB_TO_PLUNGER)
|
||||
{
|
||||
float force = m_owner->getKartProperties()->getRubberBandForce() *
|
||||
m_owner->getPlayerDifficulty()->getRubberBandForce();
|
||||
float force = kp->getPlungerBandForce();
|
||||
Vec3 diff = m_end_position-k;
|
||||
|
||||
// detach rubber band if kart gets very close to hit point
|
||||
@ -180,12 +180,10 @@ void RubberBand::update(float dt)
|
||||
diff.normalize(); // diff can't be zero here
|
||||
m_owner->getBody()->applyCentralForce(diff*force);
|
||||
m_owner->increaseMaxSpeed(MaxSpeed::MS_INCREASE_RUBBER,
|
||||
m_owner->getKartProperties()->getRubberBandSpeedIncrease() *
|
||||
m_owner->getPlayerDifficulty()->getRubberBandSpeedIncrease(),
|
||||
kp->getPlungerBandSpeedIncrease(),
|
||||
/*engine_force*/ 0.0f,
|
||||
/*duration*/0.1f,
|
||||
m_owner->getKartProperties()->getRubberBandFadeOutTime() *
|
||||
m_owner->getPlayerDifficulty()->getRubberBandFadeOutTime());
|
||||
kp->getPlungerBandFadeOutTime());
|
||||
if(m_attached_state==RB_TO_KART)
|
||||
m_hit_kart->getBody()->applyCentralForce(diff*(-force));
|
||||
}
|
||||
|
@ -59,7 +59,10 @@ Swatter::Swatter(AbstractKart *kart, bool was_bomb,
|
||||
: AttachmentPlugin(kart)
|
||||
{
|
||||
m_animation_phase = SWATTER_AIMING;
|
||||
m_discard_now = false;
|
||||
m_discard_timeout = 0.0f;
|
||||
m_target = NULL;
|
||||
m_closest_kart = NULL;
|
||||
m_removing_bomb = was_bomb;
|
||||
m_bomb_scene_node = bomb_scene_node;
|
||||
m_swat_bomb_frame = 0.0f;
|
||||
@ -112,89 +115,106 @@ Swatter::~Swatter()
|
||||
*/
|
||||
bool Swatter::updateAndTestFinished(float dt)
|
||||
{
|
||||
if (m_removing_bomb)
|
||||
if (!m_discard_now)
|
||||
{
|
||||
m_swat_bomb_frame += dt*25.0f;
|
||||
m_scene_node->setRotation(core::vector3df(0.0, -180.0, 0.0));
|
||||
|
||||
m_scene_node->setCurrentFrame(m_swat_bomb_frame);
|
||||
|
||||
if (m_swat_bomb_frame >= 32.5f && m_bomb_scene_node != NULL)
|
||||
if (m_removing_bomb)
|
||||
{
|
||||
m_bomb_scene_node->setPosition(m_bomb_scene_node->getPosition() +
|
||||
core::vector3df(-dt*15.0f, 0.0f, 0.0f) );
|
||||
m_bomb_scene_node->setRotation(m_bomb_scene_node->getRotation() +
|
||||
core::vector3df(-dt*15.0f, 0.0f, 0.0f) );
|
||||
}
|
||||
m_swat_bomb_frame += dt*25.0f;
|
||||
m_scene_node->setRotation(core::vector3df(0.0, -180.0, 0.0));
|
||||
|
||||
if (m_swat_bomb_frame >= m_scene_node->getEndFrame())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (m_swat_bomb_frame >= 35)
|
||||
{
|
||||
if (m_bomb_scene_node != NULL)
|
||||
m_scene_node->setCurrentFrame(m_swat_bomb_frame);
|
||||
|
||||
if (m_swat_bomb_frame >= 32.5f && m_bomb_scene_node != NULL)
|
||||
{
|
||||
irr_driver->removeNode(m_bomb_scene_node);
|
||||
m_bomb_scene_node = NULL;
|
||||
m_bomb_scene_node->setPosition(m_bomb_scene_node
|
||||
->getPosition() + core::vector3df(-dt*15.0f, 0.0f, 0.0f) );
|
||||
m_bomb_scene_node->setRotation(m_bomb_scene_node
|
||||
->getRotation() + core::vector3df(-dt*15.0f, 0.0f, 0.0f) );
|
||||
}
|
||||
} // bom_frame > 35
|
||||
|
||||
return false;
|
||||
} // if removing bomb
|
||||
|
||||
switch(m_animation_phase)
|
||||
{
|
||||
case SWATTER_AIMING:
|
||||
{
|
||||
chooseTarget();
|
||||
pointToTarget();
|
||||
if(!m_target) break;
|
||||
|
||||
// Is the target too near?
|
||||
float dist_to_target2 =
|
||||
(m_target->getXYZ()- Vec3(m_scene_node->getAbsolutePosition()))
|
||||
.length2();
|
||||
float min_dist2
|
||||
= m_kart->getKartProperties()->getSwatterDistance2();
|
||||
if(dist_to_target2 < min_dist2)
|
||||
if (m_swat_bomb_frame >= m_scene_node->getEndFrame())
|
||||
{
|
||||
// Start squashing
|
||||
m_animation_phase = SWATTER_TO_TARGET;
|
||||
|
||||
// Setup the animation
|
||||
m_scene_node->setCurrentFrame(0.0f);
|
||||
m_scene_node->setLoopMode(false);
|
||||
m_scene_node->setAnimationSpeed(SWATTER_ANIMATION_SPEED);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SWATTER_TO_TARGET:
|
||||
{
|
||||
pointToTarget();
|
||||
|
||||
const float middle_frame = m_scene_node->getEndFrame()/2.0f;
|
||||
float current_frame = m_scene_node->getFrameNr();
|
||||
|
||||
// Did we just finish the first part of the movement?
|
||||
if(current_frame >= middle_frame)
|
||||
else if (m_swat_bomb_frame >= 35)
|
||||
{
|
||||
// Squash the karts and items around and
|
||||
// change the current phase
|
||||
squashThingsAround();
|
||||
m_animation_phase = SWATTER_FROM_TARGET;
|
||||
}
|
||||
}
|
||||
break;
|
||||
if (m_bomb_scene_node != NULL)
|
||||
{
|
||||
irr_driver->removeNode(m_bomb_scene_node);
|
||||
m_bomb_scene_node = NULL;
|
||||
}
|
||||
} // bom_frame > 35
|
||||
|
||||
case SWATTER_FROM_TARGET:
|
||||
break;
|
||||
return false;
|
||||
} // if removing bomb
|
||||
|
||||
switch(m_animation_phase)
|
||||
{
|
||||
case SWATTER_AIMING:
|
||||
{
|
||||
chooseTarget();
|
||||
pointToTarget();
|
||||
if(!m_target || !m_closest_kart) break;
|
||||
|
||||
// Get the node corresponding to the joint at the center of the
|
||||
// swatter (by swatter, I mean the thing hold in the hand, not
|
||||
// the whole thing)
|
||||
scene::ISceneNode* swatter_node =
|
||||
m_scene_node->getJointNode("Swatter");
|
||||
assert(swatter_node);
|
||||
Vec3 swatter_pos = swatter_node->getAbsolutePosition();
|
||||
float dist2 = (m_closest_kart->getXYZ()-swatter_pos).length2();
|
||||
float min_dist2
|
||||
= m_kart->getKartProperties()->getSwatterDistance();
|
||||
|
||||
if(dist2 < min_dist2)
|
||||
{
|
||||
// Start squashing
|
||||
m_animation_phase = SWATTER_TO_TARGET;
|
||||
|
||||
// Setup the animation
|
||||
m_scene_node->setCurrentFrame(0.0f);
|
||||
m_scene_node->setLoopMode(false);
|
||||
m_scene_node->setAnimationSpeed(SWATTER_ANIMATION_SPEED);
|
||||
|
||||
// Play swat sound
|
||||
m_swat_sound->setPosition(swatter_pos);
|
||||
m_swat_sound->play();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SWATTER_TO_TARGET:
|
||||
{
|
||||
pointToTarget();
|
||||
const float middle_frame = m_scene_node->getEndFrame()/2.0f;
|
||||
float current_frame = m_scene_node->getFrameNr();
|
||||
|
||||
// Did we just finish the first part of the movement?
|
||||
if(current_frame >= middle_frame)
|
||||
{
|
||||
// Squash the karts and items around and
|
||||
// change the current phase
|
||||
squashThingsAround();
|
||||
m_animation_phase = SWATTER_FROM_TARGET;
|
||||
if (race_manager->getMinorMode()==
|
||||
RaceManager::MINOR_MODE_3_STRIKES)
|
||||
{
|
||||
// Remove swatter from kart in 3 strikes battle
|
||||
// after one successful hit
|
||||
m_discard_now = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SWATTER_FROM_TARGET:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
m_discard_timeout += dt;
|
||||
|
||||
// If the swatter is used up, trigger cleaning up
|
||||
// TODO: use a timeout
|
||||
// TODO: how does it work currently...?
|
||||
return false;
|
||||
return (m_discard_now && m_discard_timeout > 0.5f ? true : false);
|
||||
} // updateAndTestFinished
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -234,6 +254,7 @@ void Swatter::chooseTarget()
|
||||
}
|
||||
}
|
||||
m_target = closest_kart; // may be NULL
|
||||
m_closest_kart = closest_kart;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -264,58 +285,30 @@ void Swatter::pointToTarget()
|
||||
*/
|
||||
void Swatter::squashThingsAround()
|
||||
{
|
||||
const KartProperties* kp = m_kart->getKartProperties();
|
||||
// Square of the minimum distance
|
||||
float min_dist2 = kp->getSwatterDistance2();
|
||||
const World* world = World::getWorld();
|
||||
const KartProperties *kp = m_kart->getKartProperties();
|
||||
|
||||
// Get the node corresponding to the joint at the center of the swatter
|
||||
// (by swatter, I mean the thing hold in the hand, not the whole thing)
|
||||
scene::ISceneNode* swatter_node = m_scene_node->getJointNode("Swatter");
|
||||
assert(swatter_node);
|
||||
Vec3 swatter_pos = swatter_node->getAbsolutePosition();
|
||||
m_closest_kart->setSquash(kp->getSwatterSquashDuration(),
|
||||
kp->getSwatterSquashSlowdown());
|
||||
|
||||
m_swat_sound->setPosition(swatter_pos);
|
||||
m_swat_sound->play();
|
||||
|
||||
// Squash karts around
|
||||
for(unsigned int i=0; i<world->getNumKarts(); i++)
|
||||
//Handle achievement if the swatter is used by the current player
|
||||
const StateManager::ActivePlayer *const ap = m_kart->getController()
|
||||
->getPlayer();
|
||||
if (ap && ap->getConstProfile() == PlayerManager::getCurrentPlayer())
|
||||
{
|
||||
AbstractKart *kart = world->getKart(i);
|
||||
// TODO: isSwatterReady()
|
||||
if(kart->isEliminated() || kart==m_kart)
|
||||
continue;
|
||||
// don't swat an already hurt kart
|
||||
if (kart->isInvulnerable() || kart->isSquashed())
|
||||
continue;
|
||||
PlayerManager::increaseAchievement(AchievementInfo::ACHIEVE_MOSQUITO,
|
||||
"swatter", 1);
|
||||
}
|
||||
|
||||
float dist2 = (kart->getXYZ()-swatter_pos).length2();
|
||||
|
||||
if(dist2 >= min_dist2) continue; // too far away, ignore this kart
|
||||
|
||||
kart->setSquash(kp->getSquashDuration() * kart->getPlayerDifficulty()->getSquashDuration(),
|
||||
kp->getSquashSlowdown() * kart->getPlayerDifficulty()->getSquashSlowdown());
|
||||
|
||||
//Handle achievement if the swatter is used by the current player
|
||||
const StateManager::ActivePlayer *const ap = m_kart->getController()
|
||||
->getPlayer();
|
||||
if (ap && ap->getConstProfile() == PlayerManager::getCurrentPlayer())
|
||||
{
|
||||
PlayerManager::increaseAchievement(AchievementInfo::ACHIEVE_MOSQUITO,
|
||||
"swatter", 1);
|
||||
}
|
||||
|
||||
if (kart->getAttachment()->getType()==Attachment::ATTACH_BOMB)
|
||||
{ // make bomb explode
|
||||
kart->getAttachment()->update(10000);
|
||||
HitEffect *he = new Explosion(m_kart->getXYZ(), "explosion", "explosion.xml");
|
||||
if(m_kart->getController()->isPlayerController())
|
||||
he->setPlayerKartHit();
|
||||
projectile_manager->addHitEffect(he);
|
||||
ExplosionAnimation::create(kart);
|
||||
} // if kart has bomb attached
|
||||
World::getWorld()->kartHit(kart->getWorldKartId());
|
||||
} // for i < num_kartrs
|
||||
if (m_closest_kart->getAttachment()->getType()==Attachment::ATTACH_BOMB)
|
||||
{ // make bomb explode
|
||||
m_closest_kart->getAttachment()->update(10000);
|
||||
HitEffect *he = new Explosion(m_kart->getXYZ(), "explosion", "explosion.xml");
|
||||
if(m_kart->getController()->isPlayerController())
|
||||
he->setPlayerKartHit();
|
||||
projectile_manager->addHitEffect(he);
|
||||
ExplosionAnimation::create(m_closest_kart);
|
||||
} // if kart has bomb attached
|
||||
World::getWorld()->kartHit(m_closest_kart->getWorldKartId());
|
||||
|
||||
// TODO: squash items
|
||||
} // squashThingsAround
|
||||
|
@ -49,9 +49,17 @@ private:
|
||||
enum {SWATTER_AIMING, SWATTER_TO_TARGET, SWATTER_FROM_TARGET}
|
||||
m_animation_phase;
|
||||
|
||||
/** True if the swatter will be discarded now. */
|
||||
bool m_discard_now;
|
||||
|
||||
/** Require for the sfx to complete. */
|
||||
float m_discard_timeout;
|
||||
|
||||
/** The kart the swatter is aiming at. */
|
||||
Moveable *m_target;
|
||||
|
||||
AbstractKart *m_closest_kart;
|
||||
|
||||
SFXBase *m_swat_sound;
|
||||
|
||||
/** True if the swatter is removing an attached bomb. */
|
||||
|
1723
src/karts/abstract_characteristic.cpp
Executable file
1723
src/karts/abstract_characteristic.cpp
Executable file
File diff suppressed because it is too large
Load Diff
383
src/karts/abstract_characteristic.hpp
Executable file
383
src/karts/abstract_characteristic.hpp
Executable file
@ -0,0 +1,383 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2006-2015 SuperTuxKart-Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#ifndef HEADER_ABSTRACT_CHARACTERISTICS_HPP
|
||||
#define HEADER_ABSTRACT_CHARACTERISTICS_HPP
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class InterpolationArray;
|
||||
|
||||
/**
|
||||
* Characteristics are the properties of a kart that influence
|
||||
* gameplay mechanics.
|
||||
* The biggest parts are:
|
||||
* - Physics
|
||||
* - Visuals
|
||||
* - Items
|
||||
* - and miscellaneous properties like nitro and startup boost.
|
||||
*
|
||||
* The documentation of these properties can be found in
|
||||
* the kart_characteristics.xml file.
|
||||
* Large parts of this file are generated by tools/create_kart_properties.py.
|
||||
* Please don't change the generated code here, instead change the script,
|
||||
* regenerate the code and overwrite the whole generated part with the result.
|
||||
*/
|
||||
class AbstractCharacteristic
|
||||
{
|
||||
public:
|
||||
union Value
|
||||
{
|
||||
float *f;
|
||||
bool *b;
|
||||
std::vector<float> *fv;
|
||||
InterpolationArray *ia;
|
||||
|
||||
Value(float *f) : f(f) {}
|
||||
Value(bool *b) : b(b) {}
|
||||
Value(std::vector<float> *fv) : fv(fv) {}
|
||||
Value(InterpolationArray *ia) : ia(ia) {}
|
||||
};
|
||||
|
||||
enum ValueType
|
||||
{
|
||||
TYPE_FLOAT,
|
||||
TYPE_BOOL,
|
||||
TYPE_FLOAT_VECTOR,
|
||||
TYPE_INTERPOLATION_ARRAY
|
||||
};
|
||||
|
||||
enum CharacteristicType
|
||||
{
|
||||
// Script-generated content generated by tools/create_kart_properties.py enum
|
||||
// Please don't change the following tag. It will be automatically detected
|
||||
// by the script and replace the contained content.
|
||||
// To update the code, use tools/update_characteristics.py
|
||||
/* <characteristics-start enum> */
|
||||
|
||||
// Suspension
|
||||
SUSPENSION_STIFFNESS,
|
||||
SUSPENSION_REST,
|
||||
SUSPENSION_TRAVEL,
|
||||
SUSPENSION_EXP_SPRING_RESPONSE,
|
||||
SUSPENSION_MAX_FORCE,
|
||||
|
||||
// Stability
|
||||
STABILITY_ROLL_INFLUENCE,
|
||||
STABILITY_CHASSIS_LINEAR_DAMPING,
|
||||
STABILITY_CHASSIS_ANGULAR_DAMPING,
|
||||
STABILITY_DOWNWARD_IMPULSE_FACTOR,
|
||||
STABILITY_TRACK_CONNECTION_ACCEL,
|
||||
STABILITY_SMOOTH_FLYING_IMPULSE,
|
||||
|
||||
// Turn
|
||||
TURN_RADIUS,
|
||||
TURN_TIME_RESET_STEER,
|
||||
TURN_TIME_FULL_STEER,
|
||||
|
||||
// Engine
|
||||
ENGINE_POWER,
|
||||
ENGINE_MAX_SPEED,
|
||||
ENGINE_BRAKE_FACTOR,
|
||||
ENGINE_BRAKE_TIME_INCREASE,
|
||||
ENGINE_MAX_SPEED_REVERSE_RATIO,
|
||||
|
||||
// Gear
|
||||
GEAR_SWITCH_RATIO,
|
||||
GEAR_POWER_INCREASE,
|
||||
|
||||
// Mass
|
||||
MASS,
|
||||
|
||||
// Wheels
|
||||
WHEELS_DAMPING_RELAXATION,
|
||||
WHEELS_DAMPING_COMPRESSION,
|
||||
|
||||
// Camera
|
||||
CAMERA_DISTANCE,
|
||||
CAMERA_FORWARD_UP_ANGLE,
|
||||
CAMERA_BACKWARD_UP_ANGLE,
|
||||
|
||||
// Jump
|
||||
JUMP_ANIMATION_TIME,
|
||||
|
||||
// Lean
|
||||
LEAN_MAX,
|
||||
LEAN_SPEED,
|
||||
|
||||
// Anvil
|
||||
ANVIL_DURATION,
|
||||
ANVIL_WEIGHT,
|
||||
ANVIL_SPEED_FACTOR,
|
||||
|
||||
// Parachute
|
||||
PARACHUTE_FRICTION,
|
||||
PARACHUTE_DURATION,
|
||||
PARACHUTE_DURATION_OTHER,
|
||||
PARACHUTE_LBOUND_FRACTION,
|
||||
PARACHUTE_UBOUND_FRACTION,
|
||||
PARACHUTE_MAX_SPEED,
|
||||
|
||||
// Bubblegum
|
||||
BUBBLEGUM_DURATION,
|
||||
BUBBLEGUM_SPEED_FRACTION,
|
||||
BUBBLEGUM_TORQUE,
|
||||
BUBBLEGUM_FADE_IN_TIME,
|
||||
BUBBLEGUM_SHIELD_DURATION,
|
||||
|
||||
// Zipper
|
||||
ZIPPER_DURATION,
|
||||
ZIPPER_FORCE,
|
||||
ZIPPER_SPEED_GAIN,
|
||||
ZIPPER_MAX_SPEED_INCREASE,
|
||||
ZIPPER_FADE_OUT_TIME,
|
||||
|
||||
// Swatter
|
||||
SWATTER_DURATION,
|
||||
SWATTER_DISTANCE,
|
||||
SWATTER_SQUASH_DURATION,
|
||||
SWATTER_SQUASH_SLOWDOWN,
|
||||
|
||||
// Plunger
|
||||
PLUNGER_BAND_MAX_LENGTH,
|
||||
PLUNGER_BAND_FORCE,
|
||||
PLUNGER_BAND_DURATION,
|
||||
PLUNGER_BAND_SPEED_INCREASE,
|
||||
PLUNGER_BAND_FADE_OUT_TIME,
|
||||
PLUNGER_IN_FACE_TIME,
|
||||
|
||||
// Startup
|
||||
STARTUP_TIME,
|
||||
STARTUP_BOOST,
|
||||
|
||||
// Rescue
|
||||
RESCUE_DURATION,
|
||||
RESCUE_VERT_OFFSET,
|
||||
RESCUE_HEIGHT,
|
||||
|
||||
// Explosion
|
||||
EXPLOSION_DURATION,
|
||||
EXPLOSION_RADIUS,
|
||||
EXPLOSION_INVULNERABILITY_TIME,
|
||||
|
||||
// Nitro
|
||||
NITRO_DURATION,
|
||||
NITRO_ENGINE_FORCE,
|
||||
NITRO_CONSUMPTION,
|
||||
NITRO_SMALL_CONTAINER,
|
||||
NITRO_BIG_CONTAINER,
|
||||
NITRO_MAX_SPEED_INCREASE,
|
||||
NITRO_FADE_OUT_TIME,
|
||||
NITRO_MAX,
|
||||
|
||||
// Slipstream
|
||||
SLIPSTREAM_DURATION,
|
||||
SLIPSTREAM_LENGTH,
|
||||
SLIPSTREAM_WIDTH,
|
||||
SLIPSTREAM_COLLECT_TIME,
|
||||
SLIPSTREAM_USE_TIME,
|
||||
SLIPSTREAM_ADD_POWER,
|
||||
SLIPSTREAM_MIN_SPEED,
|
||||
SLIPSTREAM_MAX_SPEED_INCREASE,
|
||||
SLIPSTREAM_FADE_OUT_TIME,
|
||||
|
||||
// Skid
|
||||
SKID_INCREASE,
|
||||
SKID_DECREASE,
|
||||
SKID_MAX,
|
||||
SKID_TIME_TILL_MAX,
|
||||
SKID_VISUAL,
|
||||
SKID_VISUAL_TIME,
|
||||
SKID_REVERT_VISUAL_TIME,
|
||||
SKID_MIN_SPEED,
|
||||
SKID_TIME_TILL_BONUS,
|
||||
SKID_BONUS_SPEED,
|
||||
SKID_BONUS_TIME,
|
||||
SKID_BONUS_FORCE,
|
||||
SKID_PHYSICAL_JUMP_TIME,
|
||||
SKID_GRAPHICAL_JUMP_TIME,
|
||||
SKID_POST_SKID_ROTATE_FACTOR,
|
||||
SKID_REDUCE_TURN_MIN,
|
||||
SKID_REDUCE_TURN_MAX,
|
||||
SKID_ENABLED,
|
||||
|
||||
/* <characteristics-end enum> */
|
||||
|
||||
|
||||
// Count
|
||||
CHARACTERISTIC_COUNT
|
||||
};
|
||||
|
||||
public:
|
||||
AbstractCharacteristic();
|
||||
virtual ~AbstractCharacteristic() {}
|
||||
|
||||
/**
|
||||
* The process function is the core of this characteristics system.
|
||||
* Any computation of the properties should happen here and modify the
|
||||
* values of the value-pointer (be sure to use the right type!) and the
|
||||
* is_set parameter when the value was set by the call (and wasn't set
|
||||
* before).
|
||||
*
|
||||
* \param type The characteristic that should be modified.
|
||||
* \param value The current value and result at the same time.
|
||||
* \param is_set If the current value was already set (so it can be used
|
||||
* for computations).
|
||||
*/
|
||||
virtual void process(CharacteristicType type, Value value, bool *is_set) const;
|
||||
|
||||
static ValueType getType(CharacteristicType type);
|
||||
static std::string getName(CharacteristicType type);
|
||||
|
||||
|
||||
// Script-generated content generated by tools/create_kart_properties.py defs
|
||||
// Please don't change the following tag. It will be automatically detected
|
||||
// by the script and replace the contained content.
|
||||
// To update the code, use tools/update_characteristics.py
|
||||
/* <characteristics-start acdefs> */
|
||||
|
||||
float getSuspensionStiffness() const;
|
||||
float getSuspensionRest() const;
|
||||
float getSuspensionTravel() const;
|
||||
bool getSuspensionExpSpringResponse() const;
|
||||
float getSuspensionMaxForce() const;
|
||||
|
||||
float getStabilityRollInfluence() const;
|
||||
float getStabilityChassisLinearDamping() const;
|
||||
float getStabilityChassisAngularDamping() const;
|
||||
float getStabilityDownwardImpulseFactor() const;
|
||||
float getStabilityTrackConnectionAccel() const;
|
||||
float getStabilitySmoothFlyingImpulse() const;
|
||||
|
||||
InterpolationArray getTurnRadius() const;
|
||||
float getTurnTimeResetSteer() const;
|
||||
InterpolationArray getTurnTimeFullSteer() const;
|
||||
|
||||
float getEnginePower() const;
|
||||
float getEngineMaxSpeed() const;
|
||||
float getEngineBrakeFactor() const;
|
||||
float getEngineBrakeTimeIncrease() const;
|
||||
float getEngineMaxSpeedReverseRatio() const;
|
||||
|
||||
std::vector<float> getGearSwitchRatio() const;
|
||||
std::vector<float> getGearPowerIncrease() const;
|
||||
|
||||
float getMass() const;
|
||||
|
||||
float getWheelsDampingRelaxation() const;
|
||||
float getWheelsDampingCompression() const;
|
||||
|
||||
float getCameraDistance() const;
|
||||
float getCameraForwardUpAngle() const;
|
||||
float getCameraBackwardUpAngle() const;
|
||||
|
||||
float getJumpAnimationTime() const;
|
||||
|
||||
float getLeanMax() const;
|
||||
float getLeanSpeed() const;
|
||||
|
||||
float getAnvilDuration() const;
|
||||
float getAnvilWeight() const;
|
||||
float getAnvilSpeedFactor() const;
|
||||
|
||||
float getParachuteFriction() const;
|
||||
float getParachuteDuration() const;
|
||||
float getParachuteDurationOther() const;
|
||||
float getParachuteLboundFraction() const;
|
||||
float getParachuteUboundFraction() const;
|
||||
float getParachuteMaxSpeed() const;
|
||||
|
||||
float getBubblegumDuration() const;
|
||||
float getBubblegumSpeedFraction() const;
|
||||
float getBubblegumTorque() const;
|
||||
float getBubblegumFadeInTime() const;
|
||||
float getBubblegumShieldDuration() const;
|
||||
|
||||
float getZipperDuration() const;
|
||||
float getZipperForce() const;
|
||||
float getZipperSpeedGain() const;
|
||||
float getZipperMaxSpeedIncrease() const;
|
||||
float getZipperFadeOutTime() const;
|
||||
|
||||
float getSwatterDuration() const;
|
||||
float getSwatterDistance() const;
|
||||
float getSwatterSquashDuration() const;
|
||||
float getSwatterSquashSlowdown() const;
|
||||
|
||||
float getPlungerBandMaxLength() const;
|
||||
float getPlungerBandForce() const;
|
||||
float getPlungerBandDuration() const;
|
||||
float getPlungerBandSpeedIncrease() const;
|
||||
float getPlungerBandFadeOutTime() const;
|
||||
float getPlungerInFaceTime() const;
|
||||
|
||||
std::vector<float> getStartupTime() const;
|
||||
std::vector<float> getStartupBoost() const;
|
||||
|
||||
float getRescueDuration() const;
|
||||
float getRescueVertOffset() const;
|
||||
float getRescueHeight() const;
|
||||
|
||||
float getExplosionDuration() const;
|
||||
float getExplosionRadius() const;
|
||||
float getExplosionInvulnerabilityTime() const;
|
||||
|
||||
float getNitroDuration() const;
|
||||
float getNitroEngineForce() const;
|
||||
float getNitroConsumption() const;
|
||||
float getNitroSmallContainer() const;
|
||||
float getNitroBigContainer() const;
|
||||
float getNitroMaxSpeedIncrease() const;
|
||||
float getNitroFadeOutTime() const;
|
||||
float getNitroMax() const;
|
||||
|
||||
float getSlipstreamDuration() const;
|
||||
float getSlipstreamLength() const;
|
||||
float getSlipstreamWidth() const;
|
||||
float getSlipstreamCollectTime() const;
|
||||
float getSlipstreamUseTime() const;
|
||||
float getSlipstreamAddPower() const;
|
||||
float getSlipstreamMinSpeed() const;
|
||||
float getSlipstreamMaxSpeedIncrease() const;
|
||||
float getSlipstreamFadeOutTime() const;
|
||||
|
||||
float getSkidIncrease() const;
|
||||
float getSkidDecrease() const;
|
||||
float getSkidMax() const;
|
||||
float getSkidTimeTillMax() const;
|
||||
float getSkidVisual() const;
|
||||
float getSkidVisualTime() const;
|
||||
float getSkidRevertVisualTime() const;
|
||||
float getSkidMinSpeed() const;
|
||||
std::vector<float> getSkidTimeTillBonus() const;
|
||||
std::vector<float> getSkidBonusSpeed() const;
|
||||
std::vector<float> getSkidBonusTime() const;
|
||||
std::vector<float> getSkidBonusForce() const;
|
||||
float getSkidPhysicalJumpTime() const;
|
||||
float getSkidGraphicalJumpTime() const;
|
||||
float getSkidPostSkidRotateFactor() const;
|
||||
float getSkidReduceTurnMin() const;
|
||||
float getSkidReduceTurnMax() const;
|
||||
bool getSkidEnabled() const;
|
||||
|
||||
/* <characteristics-end acdefs> */
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -35,14 +35,15 @@
|
||||
AbstractKart::AbstractKart(const std::string& ident,
|
||||
int world_kart_id, int position,
|
||||
const btTransform& init_transform,
|
||||
const PlayerDifficulty *difficulty)
|
||||
PerPlayerDifficulty difficulty)
|
||||
: Moveable()
|
||||
{
|
||||
m_world_kart_id = world_kart_id;
|
||||
m_kart_properties = kart_properties_manager->getKart(ident);
|
||||
m_kart_properties.reset(new KartProperties());
|
||||
m_kart_properties->copyForPlayer(kart_properties_manager->getKart(ident));
|
||||
m_difficulty = difficulty;
|
||||
m_kart_animation = NULL;
|
||||
assert(m_kart_properties != NULL);
|
||||
assert(m_kart_properties);
|
||||
|
||||
// We have to take a copy of the kart model, since otherwise
|
||||
// the animations will be mixed up (i.e. different instances of
|
||||
|
@ -19,10 +19,11 @@
|
||||
#ifndef HEADER_ABSTRACT_KART_HPP
|
||||
#define HEADER_ABSTRACT_KART_HPP
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "items/powerup_manager.hpp"
|
||||
#include "karts/moveable.hpp"
|
||||
#include "karts/controller/kart_control.hpp"
|
||||
#include "karts/player_difficulty.hpp"
|
||||
#include "race/race_manager.hpp"
|
||||
|
||||
namespace irr
|
||||
@ -70,10 +71,10 @@ private:
|
||||
|
||||
protected:
|
||||
/** The kart properties. */
|
||||
const KartProperties *m_kart_properties;
|
||||
std::unique_ptr<KartProperties> m_kart_properties;
|
||||
|
||||
/** The per-player difficulty. */
|
||||
const PlayerDifficulty *m_difficulty;
|
||||
PerPlayerDifficulty m_difficulty;
|
||||
|
||||
/** This stores a copy of the kart model. It has to be a copy
|
||||
* since otherwise incosistencies can happen if the same kart
|
||||
@ -95,7 +96,7 @@ public:
|
||||
AbstractKart(const std::string& ident,
|
||||
int world_kart_id,
|
||||
int position, const btTransform& init_transform,
|
||||
const PlayerDifficulty *difficulty);
|
||||
PerPlayerDifficulty difficulty);
|
||||
virtual ~AbstractKart();
|
||||
virtual core::stringw getName() const;
|
||||
virtual void reset();
|
||||
@ -120,20 +121,17 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the kart properties of this kart. */
|
||||
const KartProperties* getKartProperties() const
|
||||
{ return m_kart_properties; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets the kart properties. */
|
||||
void setKartProperties(const KartProperties *kp) { m_kart_properties=kp; }
|
||||
{ return m_kart_properties.get(); }
|
||||
|
||||
// ========================================================================
|
||||
// Access to the per-player difficulty.
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the per-player difficulty of this kart. */
|
||||
const PlayerDifficulty* getPlayerDifficulty() const
|
||||
const PerPlayerDifficulty getPerPlayerDifficulty() const
|
||||
{ return m_difficulty; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets the per-player difficulty. */
|
||||
void setPlayerDifficulty(const PlayerDifficulty *pd) { m_difficulty=pd; }
|
||||
void setPerPlayerDifficulty(const PerPlayerDifficulty d) { m_difficulty=d; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns a unique identifier for this kart (name of the directory the
|
||||
@ -144,6 +142,10 @@ public:
|
||||
* speed. */
|
||||
virtual float getMaxSteerAngle () const = 0;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the (maximum) speed for a given turn radius.
|
||||
* \param radius The radius for which the speed needs to be computed. */
|
||||
virtual float getSpeedForTurnRadius(float radius) const = 0;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the time till full steering is reached for this kart.
|
||||
* This can depend on the current steering value, which must be >= 0.
|
||||
*/
|
||||
@ -445,6 +447,9 @@ public:
|
||||
/** Counter which is used for displaying wrong way message after a delay */
|
||||
virtual float getWrongwayCounter() = 0;
|
||||
virtual void setWrongwayCounter(float counter) = 0;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns whether this kart wins or loses. */
|
||||
virtual bool getRaceResult() const = 0;
|
||||
|
||||
}; // AbstractKart
|
||||
|
||||
|
203
src/karts/cached_characteristic.cpp
Normal file
203
src/karts/cached_characteristic.cpp
Normal file
@ -0,0 +1,203 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2006-2015 SuperTuxKart-Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#include "karts/cached_characteristic.hpp"
|
||||
|
||||
#include "utils/interpolation_array.hpp"
|
||||
|
||||
CachedCharacteristic::CachedCharacteristic(const AbstractCharacteristic *origin) :
|
||||
m_values(CHARACTERISTIC_COUNT),
|
||||
m_origin(origin)
|
||||
{
|
||||
updateSource();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Deletes all allocated values. */
|
||||
CachedCharacteristic::~CachedCharacteristic()
|
||||
{
|
||||
// Delete all not-null values
|
||||
for (int i = 0; i < CHARACTERISTIC_COUNT; i++)
|
||||
{
|
||||
SaveValue &v = m_values[i];
|
||||
if (v.content)
|
||||
{
|
||||
switch (getType(static_cast<CharacteristicType>(i)))
|
||||
{
|
||||
case TYPE_FLOAT:
|
||||
delete static_cast<float*>(v.content);
|
||||
break;
|
||||
case TYPE_FLOAT_VECTOR:
|
||||
delete static_cast<std::vector<float>*>(v.content);
|
||||
break;
|
||||
case TYPE_INTERPOLATION_ARRAY:
|
||||
delete static_cast<InterpolationArray*>(v.content);
|
||||
break;
|
||||
case TYPE_BOOL:
|
||||
delete static_cast<bool*>(v.content);
|
||||
break;
|
||||
}
|
||||
v.content = nullptr;
|
||||
}
|
||||
}
|
||||
} // ~CachedCharacteristic
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Recompute the values of all characteristics based on the list of
|
||||
* source-characteristics.
|
||||
*/
|
||||
void CachedCharacteristic::updateSource()
|
||||
{
|
||||
for (int i = 0; i < CHARACTERISTIC_COUNT; i++)
|
||||
{
|
||||
SaveValue &v = m_values[i];
|
||||
|
||||
bool is_set = false;
|
||||
switch (getType(static_cast<CharacteristicType>(i)))
|
||||
{
|
||||
case TYPE_FLOAT:
|
||||
{
|
||||
float value;
|
||||
float *ptr = static_cast<float*>(v.content);
|
||||
m_origin->process(static_cast<CharacteristicType>(i), &value, &is_set);
|
||||
if (is_set)
|
||||
{
|
||||
if (!ptr)
|
||||
{
|
||||
float *newPtr = new float();
|
||||
v.content = newPtr;
|
||||
ptr = newPtr;
|
||||
}
|
||||
*ptr = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
delete ptr;
|
||||
v.content = nullptr;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TYPE_FLOAT_VECTOR:
|
||||
{
|
||||
std::vector<float> value;
|
||||
std::vector<float> *ptr = static_cast<std::vector<float>*>(v.content);
|
||||
m_origin->process(static_cast<CharacteristicType>(i), &value, &is_set);
|
||||
if (is_set)
|
||||
{
|
||||
if (!ptr)
|
||||
{
|
||||
std::vector<float> *newPtr = new std::vector<float>();
|
||||
v.content = newPtr;
|
||||
ptr = newPtr;
|
||||
}
|
||||
*ptr = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
delete ptr;
|
||||
v.content = nullptr;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TYPE_INTERPOLATION_ARRAY:
|
||||
{
|
||||
InterpolationArray value;
|
||||
InterpolationArray *ptr = static_cast<InterpolationArray*>(v.content);
|
||||
m_origin->process(static_cast<CharacteristicType>(i), &value, &is_set);
|
||||
if (is_set)
|
||||
{
|
||||
if (!ptr)
|
||||
{
|
||||
InterpolationArray *newPtr = new InterpolationArray();
|
||||
v.content = newPtr;
|
||||
ptr = newPtr;
|
||||
}
|
||||
*ptr = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
delete ptr;
|
||||
v.content = nullptr;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TYPE_BOOL:
|
||||
{
|
||||
bool value;
|
||||
bool *ptr = static_cast<bool*>(v.content);
|
||||
m_origin->process(static_cast<CharacteristicType>(i), &value, &is_set);
|
||||
if (is_set)
|
||||
{
|
||||
if (!ptr)
|
||||
{
|
||||
bool *newPtr = new bool();
|
||||
v.content = newPtr;
|
||||
ptr = newPtr;
|
||||
}
|
||||
*ptr = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
delete ptr;
|
||||
v.content = nullptr;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
} // switch (type)
|
||||
} // foreach characteristic
|
||||
} // updateSource
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Returns the stored value. */
|
||||
void CachedCharacteristic::process(CharacteristicType type, Value value,
|
||||
bool *is_set) const
|
||||
{
|
||||
void *v = m_values[type].content;
|
||||
if (v)
|
||||
{
|
||||
switch (getType(type))
|
||||
{
|
||||
case TYPE_FLOAT:
|
||||
*value.f = *static_cast<float*>(v);
|
||||
break;
|
||||
case TYPE_FLOAT_VECTOR:
|
||||
*value.fv = *static_cast<std::vector<float>*>(v);
|
||||
break;
|
||||
case TYPE_INTERPOLATION_ARRAY:
|
||||
*value.ia = *static_cast<InterpolationArray*>(v);
|
||||
break;
|
||||
case TYPE_BOOL:
|
||||
*value.b = *static_cast<bool*>(v);
|
||||
break;
|
||||
}
|
||||
*is_set = true;
|
||||
}
|
||||
} // process
|
||||
|
54
src/karts/cached_characteristic.hpp
Normal file
54
src/karts/cached_characteristic.hpp
Normal file
@ -0,0 +1,54 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2006-2015 SuperTuxKart-Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#ifndef HEADER_CACHED_CHARACTERISTICS_HPP
|
||||
#define HEADER_CACHED_CHARACTERISTICS_HPP
|
||||
|
||||
#include "karts/abstract_characteristic.hpp"
|
||||
|
||||
class CachedCharacteristic : public AbstractCharacteristic
|
||||
{
|
||||
private:
|
||||
/** Used to store a value. */
|
||||
struct SaveValue
|
||||
{
|
||||
void *content;
|
||||
|
||||
SaveValue() : content(nullptr) {}
|
||||
SaveValue(void *content) : content(content) {}
|
||||
};
|
||||
|
||||
/** All values for a characteristic. A nullptr means it is not set. */
|
||||
std::vector<SaveValue> m_values;
|
||||
|
||||
/** The characteristics that hold the original values. */
|
||||
const AbstractCharacteristic *m_origin;
|
||||
|
||||
public:
|
||||
CachedCharacteristic(const AbstractCharacteristic *origin);
|
||||
CachedCharacteristic(const CachedCharacteristic &characteristics) = delete;
|
||||
virtual ~CachedCharacteristic();
|
||||
|
||||
/** Fetches all cached values from the original source. */
|
||||
void updateSource();
|
||||
|
||||
virtual void process(CharacteristicType type, Value value, bool *is_set) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -69,7 +69,7 @@ CannonAnimation::~CannonAnimation()
|
||||
m_kart->getHeading() ));
|
||||
|
||||
m_kart->getBody()->setCenterOfMassTransform(pos);
|
||||
Vec3 v(0, 0, m_kart->getKartProperties()->getMaxSpeed());
|
||||
Vec3 v(0, 0, m_kart->getKartProperties()->getEngineMaxSpeed());
|
||||
m_kart->setVelocity(pos.getBasis()*v);
|
||||
} // ~CannonAnimation
|
||||
|
||||
|
35
src/karts/combined_characteristic.cpp
Normal file
35
src/karts/combined_characteristic.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2006-2015 SuperTuxKart-Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#include "karts/combined_characteristic.hpp"
|
||||
|
||||
void CombinedCharacteristic::addCharacteristic(
|
||||
const AbstractCharacteristic *characteristic)
|
||||
{
|
||||
m_childs.push_back(characteristic);
|
||||
} // addCharacteristic
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Combines all contained source characteristics. */
|
||||
void CombinedCharacteristic::process(CharacteristicType type, Value value,
|
||||
bool *is_set) const
|
||||
{
|
||||
for (const AbstractCharacteristic *characteristic : m_childs)
|
||||
characteristic->process(type, value, is_set);
|
||||
} // process
|
||||
|
36
src/karts/combined_characteristic.hpp
Normal file
36
src/karts/combined_characteristic.hpp
Normal file
@ -0,0 +1,36 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2006-2015 SuperTuxKart-Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#ifndef HEADER_COMBINDED_CHARACTERISTICS_HPP
|
||||
#define HEADER_COMBINDED_CHARACTERISTICS_HPP
|
||||
|
||||
#include "karts/abstract_characteristic.hpp"
|
||||
|
||||
class CombinedCharacteristic : public AbstractCharacteristic
|
||||
{
|
||||
private:
|
||||
std::vector<const AbstractCharacteristic*> m_childs;
|
||||
|
||||
public:
|
||||
void addCharacteristic(const AbstractCharacteristic *characteristic);
|
||||
|
||||
virtual void process(CharacteristicType type, Value value, bool *is_set) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -22,9 +22,8 @@
|
||||
#include "config/user_config.hpp"
|
||||
#include "karts/abstract_kart.hpp"
|
||||
#include "karts/kart_properties.hpp"
|
||||
#include "karts/skidding_properties.hpp"
|
||||
#include "karts/controller/ai_properties.hpp"
|
||||
#include "modes/linear_world.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
#include "utils/constants.hpp"
|
||||
|
||||
@ -32,59 +31,6 @@
|
||||
|
||||
bool AIBaseController::m_ai_debug = false;
|
||||
|
||||
/**
|
||||
This is the base class for all AIs. At this stage there are two similar
|
||||
AIs: one is the SkiddingAI, which is the AI used in lap based races
|
||||
(including follow-the-leader mode), the other one is the end controller,
|
||||
I.e. the controller that takes over from a player (or AI) when the race is
|
||||
finished.
|
||||
|
||||
This base class defines some basic operations:
|
||||
- It takes care on which part of the QuadGraph the AI currently is.
|
||||
- It determines which path the AI should take (in case of shortcuts
|
||||
or forks in the road).
|
||||
|
||||
At race start and every time a new lap is started, the AI will compute the
|
||||
path the kart is taking this lap (computePath). At this stage the decision
|
||||
which road in case of shortcut to take is purely random. It stores the
|
||||
information in two arrays:
|
||||
m_successor_index[i] stores which successor to take from node i.
|
||||
The successor is a number between 0 and number_of_successors - 1.
|
||||
m_next_node_index[i] stores the actual index of the graph node that
|
||||
follows after node i.
|
||||
Depending on operation one of the other data is more useful, so this
|
||||
class stores both information to avoid looking it up over and over.
|
||||
Once this is done (still in computePath), the array m_all_look_aheads is
|
||||
computed. This array stores for each quad a list of the next (atm) 10 quads.
|
||||
This is used when the AI is selecting where to drive next, and it will just
|
||||
pass the list of next quads to findRoadSector.
|
||||
|
||||
Note that the quad graph information is stored for every quad in the quad
|
||||
graph, even if the quad is not on the path chosen. This is necessary since
|
||||
it can happen that a kart ends up on a path not choses (e.g. perhaps it was
|
||||
pushed on that part, or couldn't get a sharp corner).
|
||||
|
||||
In update(), which gets called one per frame per AI, this object will
|
||||
determine the quad the kart is currently on (which is then used to determine
|
||||
where the kart will be driving to). This uses the m_all_look_aheads to
|
||||
speed up this process (since the kart is likely to be either on the same
|
||||
quad as it was before, or the next quad in the m_all_look_aheads list).
|
||||
|
||||
It will also check if the kart is stuck:
|
||||
this is done by maintaining a list of times when the kart hits the track. If
|
||||
(atm) more than 3 collisions happen in 1.5 seconds, the kart is considered
|
||||
stuck and will trigger a rescue (due to the pushback from the track it will
|
||||
take some time if a kart is really stuck before it will hit the track again).
|
||||
|
||||
This base class also contains some convenience functions which are useful
|
||||
in all AIs, e.g.:
|
||||
- steerToPoint: determine the steering angle to use depending on the
|
||||
current location and the point the kart is driving to.
|
||||
- normalizeAngle: To normalise the steering angle to be in [-PI,PI].
|
||||
- setSteering: Converts the steering angle into a steering fraction
|
||||
in [-1,1].
|
||||
|
||||
*/
|
||||
AIBaseController::AIBaseController(AbstractKart *kart,
|
||||
StateManager::ActivePlayer *player)
|
||||
: Controller(kart, player)
|
||||
@ -92,38 +38,24 @@ AIBaseController::AIBaseController(AbstractKart *kart,
|
||||
m_kart = kart;
|
||||
m_kart_length = m_kart->getKartLength();
|
||||
m_kart_width = m_kart->getKartWidth();
|
||||
m_ai_properties =
|
||||
m_kart->getKartProperties()->getAIPropertiesForDifficulty();
|
||||
|
||||
if(race_manager->getMinorMode()!=RaceManager::MINOR_MODE_3_STRIKES &&
|
||||
race_manager->getMinorMode()!=RaceManager::MINOR_MODE_SOCCER)
|
||||
{
|
||||
m_world = dynamic_cast<LinearWorld*>(World::getWorld());
|
||||
m_track = m_world->getTrack();
|
||||
computePath();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Those variables are not defined in a battle mode (m_world is
|
||||
// a linear world, since it assumes the existance of drivelines)
|
||||
m_world = NULL;
|
||||
m_track = NULL;
|
||||
m_next_node_index.clear();
|
||||
m_all_look_aheads.clear();
|
||||
m_successor_index.clear();
|
||||
} // if battle mode
|
||||
// Don't call our own setControllerName, since this will add a
|
||||
// billboard showing 'aibasecontroller' to the kar.
|
||||
Controller::setControllerName("AIBaseController");
|
||||
} // AIBaseController
|
||||
m_ai_properties = m_kart->getKartProperties()->getAIPropertiesForDifficulty();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void AIBaseController::reset()
|
||||
{
|
||||
m_stuck_trigger_rescue = false;
|
||||
m_stuck = false;
|
||||
m_collision_times.clear();
|
||||
} // reset
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void AIBaseController::update(float dt)
|
||||
{
|
||||
m_stuck = false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** In debug mode when the user specified --ai-debug on the command line set
|
||||
* the name of the controller as on-screen text, so that the different AI
|
||||
@ -139,210 +71,6 @@ void AIBaseController::setControllerName(const std::string &name)
|
||||
Controller::setControllerName(name);
|
||||
} // setControllerName
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Triggers a recomputation of the path to use, so that the AI does not
|
||||
* always use the same way.
|
||||
*/
|
||||
void AIBaseController::newLap(int lap)
|
||||
{
|
||||
if(lap>0)
|
||||
{
|
||||
computePath();
|
||||
}
|
||||
} // newLap
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Computes a path for the AI to follow. This function is called at race
|
||||
* start and every time a new lap is started. Recomputing the path every
|
||||
* time will mean that the kart will not always take the same path, but
|
||||
* (potentially) vary from lap to lap. At this stage the decision is done
|
||||
* randomly. The AI could be improved by collecting more information about
|
||||
* each branch of a track, and selecting the 'appropriate' one (e.g. if the
|
||||
* AI is far ahead, chose a longer/slower path).
|
||||
*/
|
||||
void AIBaseController::computePath()
|
||||
{
|
||||
m_next_node_index.resize(QuadGraph::get()->getNumNodes());
|
||||
m_successor_index.resize(QuadGraph::get()->getNumNodes());
|
||||
std::vector<unsigned int> next;
|
||||
for(unsigned int i=0; i<QuadGraph::get()->getNumNodes(); i++)
|
||||
{
|
||||
next.clear();
|
||||
// Get all successors the AI is allowed to take.
|
||||
QuadGraph::get()->getSuccessors(i, next, /*for_ai*/true);
|
||||
// In case of short cuts hidden for the AI it can be that a node
|
||||
// might not have a successor (since the first and last edge of
|
||||
// a hidden shortcut is ignored). Since in the case that the AI
|
||||
// ends up on a short cut (e.g. by accident) and doesn't have an
|
||||
// allowed way to drive, it should still be able to drive, so add
|
||||
// the non-AI successors of that node in this case.
|
||||
if(next.size()==0)
|
||||
QuadGraph::get()->getSuccessors(i, next, /*for_ai*/false);
|
||||
// For now pick one part on random, which is not adjusted during the
|
||||
// race. Long term statistics might be gathered to determine the
|
||||
// best way, potentially depending on race position etc.
|
||||
int r = rand();
|
||||
int indx = (int)( r / ((float)(RAND_MAX)+1.0f) * next.size() );
|
||||
// In case of rounding errors0
|
||||
if(indx>=(int)next.size()) indx--;
|
||||
m_successor_index[i] = indx;
|
||||
assert(indx <(int)next.size() && indx>=0);
|
||||
m_next_node_index[i] = next[indx];
|
||||
}
|
||||
|
||||
const unsigned int look_ahead=10;
|
||||
// Now compute for each node in the graph the list of the next 'look_ahead'
|
||||
// graph nodes. This is the list of node that is tested in checkCrashes.
|
||||
// If the look_ahead is too big, the AI can skip loops (see
|
||||
// QuadGraph::findRoadSector for details), if it's too short the AI won't
|
||||
// find too good a driveline. Note that in general this list should
|
||||
// be computed recursively, but since the AI for now is using only
|
||||
// (randomly picked) path this is fine
|
||||
m_all_look_aheads.resize(QuadGraph::get()->getNumNodes());
|
||||
for(unsigned int i=0; i<QuadGraph::get()->getNumNodes(); i++)
|
||||
{
|
||||
std::vector<int> l;
|
||||
int current = i;
|
||||
for(unsigned int j=0; j<look_ahead; j++)
|
||||
{
|
||||
assert(current < (int)m_next_node_index.size());
|
||||
l.push_back(m_next_node_index[current]);
|
||||
current = m_next_node_index[current];
|
||||
} // for j<look_ahead
|
||||
m_all_look_aheads[i] = l;
|
||||
}
|
||||
} // computePath
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Updates the ai base controller each time step. Note that any calls to
|
||||
* isStuck() must be done before update is called, since update will reset
|
||||
* the isStuck flag!
|
||||
* \param dt Time step size.
|
||||
*/
|
||||
void AIBaseController::update(float dt)
|
||||
{
|
||||
m_stuck_trigger_rescue = false;
|
||||
|
||||
if(QuadGraph::get())
|
||||
{
|
||||
// Update the current node:
|
||||
int old_node = m_track_node;
|
||||
if(m_track_node!=QuadGraph::UNKNOWN_SECTOR)
|
||||
{
|
||||
QuadGraph::get()->findRoadSector(m_kart->getXYZ(), &m_track_node,
|
||||
&m_all_look_aheads[m_track_node]);
|
||||
}
|
||||
// If we can't find a proper place on the track, to a broader search
|
||||
// on off-track locations.
|
||||
if(m_track_node==QuadGraph::UNKNOWN_SECTOR)
|
||||
{
|
||||
m_track_node = QuadGraph::get()->findOutOfRoadSector(m_kart->getXYZ());
|
||||
}
|
||||
// IF the AI is off track (or on a branch of the track it did not
|
||||
// select to be on), keep the old position.
|
||||
if(m_track_node==QuadGraph::UNKNOWN_SECTOR ||
|
||||
m_next_node_index[m_track_node]==-1)
|
||||
m_track_node = old_node;
|
||||
}
|
||||
} // update
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** This is called when the kart crashed with the terrain. This subroutine
|
||||
* tries to detect if the AI is stuck by determining if a certain number
|
||||
* of collisions happened in a certain amount of time, and if so rescues
|
||||
* the kart.
|
||||
* \paran m Pointer to the material that was hit (NULL if no specific
|
||||
* material was used for the part of the track that was hit).
|
||||
*/
|
||||
void AIBaseController::crashed(const Material *m)
|
||||
{
|
||||
// Defines how many collision in what time will trigger a rescue.
|
||||
// Note that typically it takes ~0.5 seconds for the AI to hit
|
||||
// the track again if it is stuck (i.e. time for the push back plus
|
||||
// time for the AI to accelerate and hit the terrain again).
|
||||
const unsigned int NUM_COLLISION = 3;
|
||||
const float COLLISION_TIME = 1.5f;
|
||||
|
||||
float time = World::getWorld()->getTime();
|
||||
if(m_collision_times.size()==0)
|
||||
{
|
||||
m_collision_times.push_back(time);
|
||||
return;
|
||||
}
|
||||
|
||||
// Filter out multiple collisions report caused by single collision
|
||||
// (bullet can report a collision more than once per frame, and
|
||||
// resolving it can take a few frames as well, causing more reported
|
||||
// collisions to happen). The time of 0.2 seconds was experimentally
|
||||
// found, typically it takes 0.5 seconds for a kart to be pushed back
|
||||
// from the terrain and accelerate to hit the same terrain again.
|
||||
if(time - m_collision_times.back() < 0.2f)
|
||||
return;
|
||||
|
||||
|
||||
// Remove all outdated entries, i.e. entries that are older than the
|
||||
// collision time plus 1 second. Older entries must be deleted,
|
||||
// otherwise a collision that happened (say) 10 seconds ago could
|
||||
// contribute to a stuck condition.
|
||||
while(m_collision_times.size()>0 &&
|
||||
time - m_collision_times[0] > 1.0f+COLLISION_TIME)
|
||||
m_collision_times.erase(m_collision_times.begin());
|
||||
|
||||
m_collision_times.push_back(time);
|
||||
|
||||
// Now detect if there are enough collision records in the
|
||||
// specified time interval.
|
||||
if(time - m_collision_times.front() > COLLISION_TIME
|
||||
&& m_collision_times.size()>=NUM_COLLISION)
|
||||
{
|
||||
// We can't call m_kart->forceRescue here, since crased() is
|
||||
// called during physics processing, and forceRescue() removes the
|
||||
// chassis from the physics world, which would then cause
|
||||
// inconsistencies and potentially a crash during the physics
|
||||
// processing. So only set a flag, which is tested during update.
|
||||
m_stuck_trigger_rescue = true;
|
||||
}
|
||||
|
||||
} // crashed(Material)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Returns the next sector of the given sector index. This is used
|
||||
* for branches in the quad graph to select which way the AI kart should
|
||||
* go. This is a very simple implementation that always returns the first
|
||||
* successor, but it can be overridden to allow a better selection.
|
||||
* \param index Index of the graph node for which the successor is searched.
|
||||
* \return Returns the successor of this graph node.
|
||||
*/
|
||||
unsigned int AIBaseController::getNextSector(unsigned int index)
|
||||
{
|
||||
std::vector<unsigned int> successors;
|
||||
QuadGraph::get()->getSuccessors(index, successors);
|
||||
return successors[0];
|
||||
} // getNextSector
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** This function steers towards a given angle. It also takes a plunger
|
||||
** attached to this kart into account by modifying the actual steer angle
|
||||
* somewhat to simulate driving without seeing.
|
||||
*/
|
||||
float AIBaseController::steerToAngle(const unsigned int sector,
|
||||
const float add_angle)
|
||||
{
|
||||
float angle = QuadGraph::get()->getAngleToNext(sector,
|
||||
getNextSector(sector));
|
||||
|
||||
//Desired angle minus current angle equals how many angles to turn
|
||||
float steer_angle = angle - m_kart->getHeading();
|
||||
|
||||
if(m_kart->getBlockedByPlungerTime()>0)
|
||||
steer_angle += add_angle*0.2f;
|
||||
else
|
||||
steer_angle += add_angle;
|
||||
steer_angle = normalizeAngle( steer_angle );
|
||||
|
||||
return steer_angle;
|
||||
} // steerToAngle
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Computes the steering angle to reach a certain point. The function will
|
||||
* request steering by setting the steering angle to maximum steer angle
|
||||
@ -493,22 +221,7 @@ void AIBaseController::setSteering(float angle, float dt)
|
||||
* AIBaseController.
|
||||
* \return True if the kart should skid.
|
||||
*/
|
||||
bool AIBaseController::doSkid(float steer_fraction)
|
||||
{
|
||||
// Disable skidding when a plunger is in the face
|
||||
if(m_kart->getBlockedByPlungerTime()>0) return false;
|
||||
|
||||
// FIXME: Disable skidding for now if the new skidding
|
||||
// code is activated, since the AI can not handle this
|
||||
// properly.
|
||||
if(m_kart->getKartProperties()->getSkiddingProperties()
|
||||
->getSkidVisualTime()>0)
|
||||
return false;
|
||||
|
||||
// Otherwise return if we need a sharp turn (which is
|
||||
// for the old skidding implementation).
|
||||
return fabsf(steer_fraction)>=m_ai_properties->m_skidding_threshold;
|
||||
} // doSkid
|
||||
// ------------------------------------------------------------------------
|
||||
/** Certain AI levels will not receive a slipstream bonus in order to
|
||||
* be not as hard.
|
||||
@ -517,3 +230,78 @@ bool AIBaseController::disableSlipstreamBonus() const
|
||||
{
|
||||
return m_ai_properties->disableSlipstreamUsage();
|
||||
} // disableSlipstreamBonus
|
||||
|
||||
|
||||
bool AIBaseController::doSkid(float steer_fraction)
|
||||
{
|
||||
// Disable skidding when a plunger is in the face
|
||||
if(m_kart->getBlockedByPlungerTime()>0) return false;
|
||||
|
||||
// FIXME: Disable skidding for now if the new skidding
|
||||
// code is activated, since the AI can not handle this
|
||||
// properly.
|
||||
if(m_kart->getKartProperties()->getSkidVisualTime() > 0)
|
||||
return false;
|
||||
|
||||
// Otherwise return if we need a sharp turn (which is
|
||||
// for the old skidding implementation).
|
||||
return fabsf(steer_fraction)>=m_ai_properties->m_skidding_threshold;
|
||||
} // doSkid
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** This is called when the kart crashed with the terrain. This subroutine
|
||||
* tries to detect if the AI is stuck by determining if a certain number
|
||||
* of collisions happened in a certain amount of time, and if so rescues
|
||||
* the kart.
|
||||
* \paran m Pointer to the material that was hit (NULL if no specific
|
||||
* material was used for the part of the track that was hit).
|
||||
*/
|
||||
void AIBaseController::crashed(const Material *m)
|
||||
{
|
||||
// Defines how many collision in what time will trigger a rescue.
|
||||
// Note that typically it takes ~0.5 seconds for the AI to hit
|
||||
// the track again if it is stuck (i.e. time for the push back plus
|
||||
// time for the AI to accelerate and hit the terrain again).
|
||||
const unsigned int NUM_COLLISION = 3;
|
||||
const float COLLISION_TIME = 1.5f;
|
||||
|
||||
float time = World::getWorld()->getTime();
|
||||
if(m_collision_times.size()==0)
|
||||
{
|
||||
m_collision_times.push_back(time);
|
||||
return;
|
||||
}
|
||||
|
||||
// Filter out multiple collisions report caused by single collision
|
||||
// (bullet can report a collision more than once per frame, and
|
||||
// resolving it can take a few frames as well, causing more reported
|
||||
// collisions to happen). The time of 0.2 seconds was experimentally
|
||||
// found, typically it takes 0.5 seconds for a kart to be pushed back
|
||||
// from the terrain and accelerate to hit the same terrain again.
|
||||
if(time - m_collision_times.back() < 0.2f)
|
||||
return;
|
||||
|
||||
// Remove all outdated entries, i.e. entries that are older than the
|
||||
// collision time plus 1 second. Older entries must be deleted,
|
||||
// otherwise a collision that happened (say) 10 seconds ago could
|
||||
// contribute to a stuck condition.
|
||||
while(m_collision_times.size()>0 &&
|
||||
time - m_collision_times[0] > 1.0f+COLLISION_TIME)
|
||||
m_collision_times.erase(m_collision_times.begin());
|
||||
|
||||
m_collision_times.push_back(time);
|
||||
|
||||
// Now detect if there are enough collision records in the
|
||||
// specified time interval.
|
||||
if(time - m_collision_times.front() > COLLISION_TIME
|
||||
&& m_collision_times.size()>=NUM_COLLISION)
|
||||
{
|
||||
// We can't call m_kart->forceRescue here, since crased() is
|
||||
// called during physics processing, and forceRescue() removes the
|
||||
// chassis from the physics world, which would then cause
|
||||
// inconsistencies and potentially a crash during the physics
|
||||
// processing. So only set a flag, which is tested during update.
|
||||
m_stuck = true;
|
||||
}
|
||||
|
||||
} // crashed(Material)
|
||||
|
@ -23,8 +23,6 @@
|
||||
#include "states_screens/state_manager.hpp"
|
||||
|
||||
class AIProperties;
|
||||
class LinearWorld;
|
||||
class QuadGraph;
|
||||
class Track;
|
||||
class Vec3;
|
||||
|
||||
@ -42,7 +40,7 @@ private:
|
||||
|
||||
/** A flag that is set during the physics processing to indicate that
|
||||
* this kart is stuck and needs to be rescued. */
|
||||
bool m_stuck_trigger_rescue;
|
||||
bool m_stuck;
|
||||
|
||||
protected:
|
||||
/** Length of the kart, storing it here saves many function calls. */
|
||||
@ -54,67 +52,30 @@ protected:
|
||||
/** Keep a pointer to the track to reduce calls */
|
||||
Track *m_track;
|
||||
|
||||
/** Keep a pointer to world. */
|
||||
LinearWorld *m_world;
|
||||
|
||||
/** A pointer to the AI properties for this kart. */
|
||||
const AIProperties *m_ai_properties;
|
||||
|
||||
/** The current node the kart is on. This can be different from the value
|
||||
* in LinearWorld, since it takes the chosen path of the AI into account
|
||||
* (e.g. the closest point in LinearWorld might be on a branch not
|
||||
* chosen by the AI). */
|
||||
int m_track_node;
|
||||
|
||||
/** Which of the successors of a node was selected by the AI. */
|
||||
std::vector<int> m_successor_index;
|
||||
/** For each node in the graph this list contains the chosen next node.
|
||||
* For normal lap track without branches we always have
|
||||
* m_next_node_index[i] = (i+1) % size;
|
||||
* but if a branch is possible, the AI will select one option here.
|
||||
* If the node is not used, m_next_node_index will be -1. */
|
||||
std::vector<int> m_next_node_index;
|
||||
/** For each graph node this list contains a list of the next X
|
||||
* graph nodes. */
|
||||
std::vector<std::vector<int> > m_all_look_aheads;
|
||||
static bool m_ai_debug;
|
||||
|
||||
virtual void update (float delta) ;
|
||||
virtual unsigned int getNextSector(unsigned int index);
|
||||
virtual void newLap (int lap);
|
||||
virtual void setControllerName(const std::string &name);
|
||||
virtual void setSteering (float angle, float dt);
|
||||
float steerToAngle (const unsigned int sector, const float angle);
|
||||
float steerToPoint (const Vec3 &point);
|
||||
void setControllerName(const std::string &name);
|
||||
float steerToPoint(const Vec3 &point);
|
||||
float normalizeAngle(float angle);
|
||||
void computePath();
|
||||
virtual bool doSkid(float steer_fraction);
|
||||
// ------------------------------------------------------------------------
|
||||
/** Nothing special to do when the race is finished. */
|
||||
virtual void raceFinished() {};
|
||||
// ------------------------------------------------------------------------
|
||||
/** This can be called to detect if the kart is stuck (i.e. repeatedly
|
||||
* hitting part of the track). */
|
||||
bool isStuck() const { return m_stuck_trigger_rescue; }
|
||||
bool isStuck() const { return m_stuck; }
|
||||
|
||||
static bool m_ai_debug;
|
||||
public:
|
||||
AIBaseController(AbstractKart *kart,
|
||||
StateManager::ActivePlayer *player=NULL);
|
||||
virtual ~AIBaseController() {};
|
||||
virtual void reset();
|
||||
static void enableDebug() {m_ai_debug = true; }
|
||||
virtual void crashed(const AbstractKart *k) {};
|
||||
virtual void crashed(const Material *m);
|
||||
virtual void handleZipper(bool play_sound) {};
|
||||
virtual void finishedRace(float time) {};
|
||||
virtual void collectedItem(const Item &item, int add_info=-1,
|
||||
float previous_energy=0) {};
|
||||
virtual void setPosition(int p) {};
|
||||
virtual bool isNetworkController() const { return false; }
|
||||
virtual bool isPlayerController() const { return false; }
|
||||
virtual void action(PlayerAction action, int value) {};
|
||||
virtual void skidBonusTriggered() {};
|
||||
virtual bool disableSlipstreamBonus() const;
|
||||
virtual void crashed(const Material *m);
|
||||
}; // AIBaseController
|
||||
|
||||
#endif
|
||||
|
262
src/karts/controller/ai_base_lap_controller.cpp
Normal file
262
src/karts/controller/ai_base_lap_controller.cpp
Normal file
@ -0,0 +1,262 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2006-2009 Eduardo Hernandez Munoz
|
||||
// Copyright (C) 2009-2015 Joerg Henrichs
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#include "karts/controller/ai_base_lap_controller.hpp"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "karts/abstract_kart.hpp"
|
||||
#include "karts/kart_properties.hpp"
|
||||
#include "karts/controller/ai_properties.hpp"
|
||||
#include "modes/linear_world.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
#include "utils/constants.hpp"
|
||||
|
||||
|
||||
/**
|
||||
This is the base class for all AIs. At this stage there are two similar
|
||||
AIs: one is the SkiddingAI, which is the AI used in lap based races
|
||||
(including follow-the-leader mode), the other one is the end controller,
|
||||
I.e. the controller that takes over from a player (or AI) when the race is
|
||||
finished.
|
||||
|
||||
This base class defines some basic operations:
|
||||
- It takes care on which part of the QuadGraph the AI currently is.
|
||||
- It determines which path the AI should take (in case of shortcuts
|
||||
or forks in the road).
|
||||
|
||||
At race start and every time a new lap is started, the AI will compute the
|
||||
path the kart is taking this lap (computePath). At this stage the decision
|
||||
which road in case of shortcut to take is purely random. It stores the
|
||||
information in two arrays:
|
||||
m_successor_index[i] stores which successor to take from node i.
|
||||
The successor is a number between 0 and number_of_successors - 1.
|
||||
m_next_node_index[i] stores the actual index of the graph node that
|
||||
follows after node i.
|
||||
Depending on operation one of the other data is more useful, so this
|
||||
class stores both information to avoid looking it up over and over.
|
||||
Once this is done (still in computePath), the array m_all_look_aheads is
|
||||
computed. This array stores for each quad a list of the next (atm) 10 quads.
|
||||
This is used when the AI is selecting where to drive next, and it will just
|
||||
pass the list of next quads to findRoadSector.
|
||||
|
||||
Note that the quad graph information is stored for every quad in the quad
|
||||
graph, even if the quad is not on the path chosen. This is necessary since
|
||||
it can happen that a kart ends up on a path not choses (e.g. perhaps it was
|
||||
pushed on that part, or couldn't get a sharp corner).
|
||||
|
||||
In update(), which gets called one per frame per AI, this object will
|
||||
determine the quad the kart is currently on (which is then used to determine
|
||||
where the kart will be driving to). This uses the m_all_look_aheads to
|
||||
speed up this process (since the kart is likely to be either on the same
|
||||
quad as it was before, or the next quad in the m_all_look_aheads list).
|
||||
|
||||
It will also check if the kart is stuck:
|
||||
this is done by maintaining a list of times when the kart hits the track. If
|
||||
(atm) more than 3 collisions happen in 1.5 seconds, the kart is considered
|
||||
stuck and will trigger a rescue (due to the pushback from the track it will
|
||||
take some time if a kart is really stuck before it will hit the track again).
|
||||
|
||||
This base class also contains some convenience functions which are useful
|
||||
in all AIs, e.g.:
|
||||
- steerToPoint: determine the steering angle to use depending on the
|
||||
current location and the point the kart is driving to.
|
||||
- normalizeAngle: To normalise the steering angle to be in [-PI,PI].
|
||||
- setSteering: Converts the steering angle into a steering fraction
|
||||
in [-1,1].
|
||||
|
||||
*/
|
||||
AIBaseLapController::AIBaseLapController(AbstractKart *kart,
|
||||
StateManager::ActivePlayer *player)
|
||||
: AIBaseController(kart, player)
|
||||
{
|
||||
|
||||
if (race_manager->getMinorMode()!=RaceManager::MINOR_MODE_3_STRIKES &&
|
||||
race_manager->getMinorMode()!=RaceManager::MINOR_MODE_SOCCER)
|
||||
{
|
||||
m_world = dynamic_cast<LinearWorld*>(World::getWorld());
|
||||
m_track = m_world->getTrack();
|
||||
computePath();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Those variables are not defined in a battle mode (m_world is
|
||||
// a linear world, since it assumes the existance of drivelines)
|
||||
m_world = NULL;
|
||||
m_track = NULL;
|
||||
m_next_node_index.clear();
|
||||
m_all_look_aheads.clear();
|
||||
m_successor_index.clear();
|
||||
} // if battle mode
|
||||
// Don't call our own setControllerName, since this will add a
|
||||
// billboard showing 'AIBaseLapController' to the kar.
|
||||
Controller::setControllerName("AIBaseLapController");
|
||||
} // AIBaseLapController
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void AIBaseLapController::reset()
|
||||
{
|
||||
AIBaseController::reset();
|
||||
} // reset
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Triggers a recomputation of the path to use, so that the AI does not
|
||||
* always use the same way.
|
||||
*/
|
||||
void AIBaseLapController::newLap(int lap)
|
||||
{
|
||||
if(lap>0)
|
||||
{
|
||||
computePath();
|
||||
}
|
||||
} // newLap
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Computes a path for the AI to follow. This function is called at race
|
||||
* start and every time a new lap is started. Recomputing the path every
|
||||
* time will mean that the kart will not always take the same path, but
|
||||
* (potentially) vary from lap to lap. At this stage the decision is done
|
||||
* randomly. The AI could be improved by collecting more information about
|
||||
* each branch of a track, and selecting the 'appropriate' one (e.g. if the
|
||||
* AI is far ahead, chose a longer/slower path).
|
||||
*/
|
||||
void AIBaseLapController::computePath()
|
||||
{
|
||||
m_next_node_index.resize(QuadGraph::get()->getNumNodes());
|
||||
m_successor_index.resize(QuadGraph::get()->getNumNodes());
|
||||
std::vector<unsigned int> next;
|
||||
for(unsigned int i=0; i<QuadGraph::get()->getNumNodes(); i++)
|
||||
{
|
||||
next.clear();
|
||||
// Get all successors the AI is allowed to take.
|
||||
QuadGraph::get()->getSuccessors(i, next, /*for_ai*/true);
|
||||
// In case of short cuts hidden for the AI it can be that a node
|
||||
// might not have a successor (since the first and last edge of
|
||||
// a hidden shortcut is ignored). Since in the case that the AI
|
||||
// ends up on a short cut (e.g. by accident) and doesn't have an
|
||||
// allowed way to drive, it should still be able to drive, so add
|
||||
// the non-AI successors of that node in this case.
|
||||
if(next.size()==0)
|
||||
QuadGraph::get()->getSuccessors(i, next, /*for_ai*/false);
|
||||
// For now pick one part on random, which is not adjusted during the
|
||||
// race. Long term statistics might be gathered to determine the
|
||||
// best way, potentially depending on race position etc.
|
||||
int r = rand();
|
||||
int indx = (int)( r / ((float)(RAND_MAX)+1.0f) * next.size() );
|
||||
// In case of rounding errors0
|
||||
if(indx>=(int)next.size()) indx--;
|
||||
m_successor_index[i] = indx;
|
||||
assert(indx <(int)next.size() && indx>=0);
|
||||
m_next_node_index[i] = next[indx];
|
||||
}
|
||||
|
||||
const unsigned int look_ahead=10;
|
||||
// Now compute for each node in the graph the list of the next 'look_ahead'
|
||||
// graph nodes. This is the list of node that is tested in checkCrashes.
|
||||
// If the look_ahead is too big, the AI can skip loops (see
|
||||
// QuadGraph::findRoadSector for details), if it's too short the AI won't
|
||||
// find too good a driveline. Note that in general this list should
|
||||
// be computed recursively, but since the AI for now is using only
|
||||
// (randomly picked) path this is fine
|
||||
m_all_look_aheads.resize(QuadGraph::get()->getNumNodes());
|
||||
for(unsigned int i=0; i<QuadGraph::get()->getNumNodes(); i++)
|
||||
{
|
||||
std::vector<int> l;
|
||||
int current = i;
|
||||
for(unsigned int j=0; j<look_ahead; j++)
|
||||
{
|
||||
assert(current < (int)m_next_node_index.size());
|
||||
l.push_back(m_next_node_index[current]);
|
||||
current = m_next_node_index[current];
|
||||
} // for j<look_ahead
|
||||
m_all_look_aheads[i] = l;
|
||||
}
|
||||
} // computePath
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Updates the ai base controller each time step. Note that any calls to
|
||||
* isStuck() must be done before update is called, since update will call
|
||||
* AIBaseController::update() which will reset the isStuck flag!
|
||||
* \param dt Time step size.
|
||||
*/
|
||||
void AIBaseLapController::update(float dt)
|
||||
{
|
||||
AIBaseController::update(dt);
|
||||
if(QuadGraph::get())
|
||||
{
|
||||
// Update the current node:
|
||||
int old_node = m_track_node;
|
||||
if(m_track_node!=QuadGraph::UNKNOWN_SECTOR)
|
||||
{
|
||||
QuadGraph::get()->findRoadSector(m_kart->getXYZ(), &m_track_node,
|
||||
&m_all_look_aheads[m_track_node]);
|
||||
}
|
||||
// If we can't find a proper place on the track, to a broader search
|
||||
// on off-track locations.
|
||||
if(m_track_node==QuadGraph::UNKNOWN_SECTOR)
|
||||
{
|
||||
m_track_node = QuadGraph::get()->findOutOfRoadSector(m_kart->getXYZ());
|
||||
}
|
||||
// IF the AI is off track (or on a branch of the track it did not
|
||||
// select to be on), keep the old position.
|
||||
if(m_track_node==QuadGraph::UNKNOWN_SECTOR ||
|
||||
m_next_node_index[m_track_node]==-1)
|
||||
m_track_node = old_node;
|
||||
}
|
||||
} // update
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Returns the next sector of the given sector index. This is used
|
||||
* for branches in the quad graph to select which way the AI kart should
|
||||
* go. This is a very simple implementation that always returns the first
|
||||
* successor, but it can be overridden to allow a better selection.
|
||||
* \param index Index of the graph node for which the successor is searched.
|
||||
* \return Returns the successor of this graph node.
|
||||
*/
|
||||
unsigned int AIBaseLapController::getNextSector(unsigned int index)
|
||||
{
|
||||
std::vector<unsigned int> successors;
|
||||
QuadGraph::get()->getSuccessors(index, successors);
|
||||
return successors[0];
|
||||
} // getNextSector
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** This function steers towards a given angle. It also takes a plunger
|
||||
** attached to this kart into account by modifying the actual steer angle
|
||||
* somewhat to simulate driving without seeing.
|
||||
*/
|
||||
float AIBaseLapController::steerToAngle(const unsigned int sector,
|
||||
const float add_angle)
|
||||
{
|
||||
float angle = QuadGraph::get()->getAngleToNext(sector,
|
||||
getNextSector(sector));
|
||||
|
||||
//Desired angle minus current angle equals how many angles to turn
|
||||
float steer_angle = angle - m_kart->getHeading();
|
||||
|
||||
if(m_kart->getBlockedByPlungerTime()>0)
|
||||
steer_angle += add_angle*0.2f;
|
||||
else
|
||||
steer_angle += add_angle;
|
||||
steer_angle = normalizeAngle( steer_angle );
|
||||
|
||||
return steer_angle;
|
||||
} // steerToAngle
|
87
src/karts/controller/ai_base_lap_controller.hpp
Normal file
87
src/karts/controller/ai_base_lap_controller.hpp
Normal file
@ -0,0 +1,87 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2010-2015 Joerg Henrichs
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#ifndef HEADER_AI_BASE_LAP_CONTROLLER_HPP
|
||||
#define HEADER_AI_BASE_LAP_CONTROLLER_HPP
|
||||
|
||||
#include "karts/controller/ai_base_controller.hpp"
|
||||
#include "states_screens/state_manager.hpp"
|
||||
|
||||
class AIProperties;
|
||||
class LinearWorld;
|
||||
class QuadGraph;
|
||||
class Track;
|
||||
class Vec3;
|
||||
|
||||
/** A base class for all AI karts. This class basically provides some
|
||||
* common low level functions.
|
||||
* \ingroup controller
|
||||
*/
|
||||
class AIBaseLapController : public AIBaseController
|
||||
{
|
||||
protected:
|
||||
/** The current node the kart is on. This can be different from the value
|
||||
* in LinearWorld, since it takes the chosen path of the AI into account
|
||||
* (e.g. the closest point in LinearWorld might be on a branch not
|
||||
* chosen by the AI). */
|
||||
int m_track_node;
|
||||
|
||||
/** Keep a pointer to world. */
|
||||
LinearWorld *m_world;
|
||||
|
||||
/** Which of the successors of a node was selected by the AI. */
|
||||
std::vector<int> m_successor_index;
|
||||
/** For each node in the graph this list contains the chosen next node.
|
||||
* For normal lap track without branches we always have
|
||||
* m_next_node_index[i] = (i+1) % size;
|
||||
* but if a branch is possible, the AI will select one option here.
|
||||
* If the node is not used, m_next_node_index will be -1. */
|
||||
std::vector<int> m_next_node_index;
|
||||
/** For each graph node this list contains a list of the next X
|
||||
* graph nodes. */
|
||||
std::vector<std::vector<int> > m_all_look_aheads;
|
||||
|
||||
virtual void update (float delta) ;
|
||||
virtual unsigned int getNextSector(unsigned int index);
|
||||
virtual void newLap (int lap);
|
||||
//virtual void setControllerName(const std::string &name);
|
||||
|
||||
float steerToAngle (const unsigned int sector, const float angle);
|
||||
|
||||
void computePath();
|
||||
// ------------------------------------------------------------------------
|
||||
/** Nothing special to do when the race is finished. */
|
||||
virtual void raceFinished() {};
|
||||
|
||||
public:
|
||||
AIBaseLapController(AbstractKart *kart,
|
||||
StateManager::ActivePlayer *player=NULL);
|
||||
virtual ~AIBaseLapController() {};
|
||||
virtual void reset();
|
||||
virtual void crashed(const AbstractKart *k) {};
|
||||
virtual void handleZipper(bool play_sound) {};
|
||||
virtual void finishedRace(float time) {};
|
||||
virtual void collectedItem(const Item &item, int add_info=-1,
|
||||
float previous_energy=0) {};
|
||||
virtual void setPosition(int p) {};
|
||||
virtual bool isNetworkController() const { return false; }
|
||||
virtual bool isPlayerController() const { return false; }
|
||||
virtual void action(PlayerAction action, int value) {};
|
||||
virtual void skidBonusTriggered() {};
|
||||
}; // AIBaseLapController
|
||||
|
||||
#endif
|
@ -43,7 +43,9 @@ public:
|
||||
protected:
|
||||
// Give them access to the members
|
||||
friend class AIBaseController;
|
||||
friend class AIBaseLapController;
|
||||
friend class SkiddingAI;
|
||||
friend class BattleAI;
|
||||
|
||||
/** Used to check that all values are defined in the xml file. */
|
||||
static float UNDEFINED;
|
||||
|
931
src/karts/controller/battle_ai.cpp
Normal file
931
src/karts/controller/battle_ai.cpp
Normal file
@ -0,0 +1,931 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2004-2005 Steve Baker <sjbaker1@airmail.net>
|
||||
// Copyright (C) 2006-2007 Eduardo Hernandez Munoz
|
||||
// Copyright (C) 2008-2015 Joerg Henrichs
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#include "karts/controller/battle_ai.hpp"
|
||||
|
||||
#include "items/attachment.hpp"
|
||||
#include "items/item_manager.hpp"
|
||||
#include "items/powerup.hpp"
|
||||
#include "items/projectile_manager.hpp"
|
||||
#include "karts/abstract_kart.hpp"
|
||||
#include "karts/controller/kart_control.hpp"
|
||||
#include "karts/controller/player_controller.hpp"
|
||||
#include "karts/controller/ai_properties.hpp"
|
||||
#include "karts/kart_properties.hpp"
|
||||
#include "karts/max_speed.hpp"
|
||||
#include "karts/rescue_animation.hpp"
|
||||
#include "karts/skidding.hpp"
|
||||
#include "modes/three_strikes_battle.hpp"
|
||||
#include "tracks/battle_graph.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
#ifdef AI_DEBUG
|
||||
#include "irrlicht.h"
|
||||
#include <iostream>
|
||||
using namespace irr;
|
||||
using namespace std;
|
||||
#endif
|
||||
|
||||
#if defined(WIN32) && !defined(__CYGWIN__) && !defined(__MINGW32__)
|
||||
#define isnan _isnan
|
||||
#else
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
BattleAI::BattleAI(AbstractKart *kart,
|
||||
StateManager::ActivePlayer *player)
|
||||
: AIBaseController(kart, player)
|
||||
{
|
||||
|
||||
reset();
|
||||
|
||||
#ifdef AI_DEBUG
|
||||
video::SColor col_debug(128, 128, 0, 0);
|
||||
m_debug_sphere = irr_driver->addSphere(1.0f, col_debug);
|
||||
m_debug_sphere->setVisible(true);
|
||||
#endif
|
||||
|
||||
if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_3_STRIKES)
|
||||
{
|
||||
m_world = dynamic_cast<ThreeStrikesBattle*>(World::getWorld());
|
||||
m_track = m_world->getTrack();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Those variables are not defined in a battle mode (m_world is
|
||||
// a linear world, since it assumes the existance of drivelines)
|
||||
m_world = NULL;
|
||||
m_track = NULL;
|
||||
}
|
||||
|
||||
// Don't call our own setControllerName, since this will add a
|
||||
// billboard showing 'AIBaseController' to the kart.
|
||||
Controller::setControllerName("BattleAI");
|
||||
|
||||
} // BattleAI
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
BattleAI::~BattleAI()
|
||||
{
|
||||
#ifdef AI_DEBUG
|
||||
irr_driver->removeNode(m_debug_sphere);
|
||||
#endif
|
||||
} // ~BattleAI
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Resets the AI when a race is restarted.
|
||||
*/
|
||||
void BattleAI::reset()
|
||||
{
|
||||
m_target_node = BattleGraph::UNKNOWN_POLY;
|
||||
m_adjusting_side = false;
|
||||
m_closest_kart = NULL;
|
||||
m_closest_kart_node = BattleGraph::UNKNOWN_POLY;
|
||||
m_closest_kart_point = Vec3(0, 0, 0);
|
||||
m_closest_kart_pos_data = {0};
|
||||
m_cur_kart_pos_data = {0};
|
||||
m_is_steering_overridden = false;
|
||||
m_is_stuck = false;
|
||||
m_is_uturn = false;
|
||||
m_target_point = Vec3(0, 0, 0);
|
||||
m_time_since_last_shot = 0.0f;
|
||||
m_time_since_driving = 0.0f;
|
||||
m_time_since_reversing = 0.0f;
|
||||
m_time_since_steering_overridden = 0.0f;
|
||||
m_time_since_uturn = 0.0f;
|
||||
m_on_node.clear();
|
||||
m_path_corners.clear();
|
||||
m_portals.clear();
|
||||
|
||||
m_cur_difficulty = race_manager->getDifficulty();
|
||||
AIBaseController::reset();
|
||||
} // reset
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** This is the main entry point for the AI.
|
||||
* It is called once per frame for each AI and determines the behaviour of
|
||||
* the AI, e.g. steering, accelerating/braking, firing.
|
||||
*/
|
||||
void BattleAI::update(float dt)
|
||||
{
|
||||
// This is used to enable firing an item backwards.
|
||||
m_controls->m_look_back = false;
|
||||
m_controls->m_nitro = false;
|
||||
|
||||
// Don't do anything if there is currently a kart animations shown.
|
||||
if (m_kart->getKartAnimation())
|
||||
return;
|
||||
|
||||
if (m_world->isStartPhase())
|
||||
{
|
||||
AIBaseController::update(dt);
|
||||
return;
|
||||
}
|
||||
|
||||
checkIfStuck(dt);
|
||||
if (m_is_stuck && !m_is_uturn)
|
||||
{
|
||||
setSteering(0.0f, dt);
|
||||
|
||||
if (fabsf(m_kart->getSpeed()) >
|
||||
(m_kart->getKartProperties()->getEngineMaxSpeed() / 5)
|
||||
&& m_kart->getSpeed() < 0)
|
||||
m_controls->m_accel = -0.06f;
|
||||
else
|
||||
m_controls->m_accel = -4.0f;
|
||||
|
||||
m_time_since_reversing += dt;
|
||||
|
||||
if (m_time_since_reversing >= 1.0f)
|
||||
{
|
||||
m_is_stuck = false;
|
||||
m_time_since_reversing = 0.0f;
|
||||
}
|
||||
AIBaseController::update(dt);
|
||||
return;
|
||||
}
|
||||
|
||||
findClosestKart(true);
|
||||
findTarget();
|
||||
handleItems(dt);
|
||||
handleBanana();
|
||||
|
||||
if (m_kart->getSpeed() > 15.0f && m_cur_kart_pos_data.angle < 0.2f)
|
||||
{
|
||||
// Only use nitro when target is straight
|
||||
m_controls->m_nitro = true;
|
||||
}
|
||||
|
||||
if (m_is_uturn)
|
||||
{
|
||||
handleUTurn(dt);
|
||||
}
|
||||
else
|
||||
{
|
||||
handleAcceleration(dt);
|
||||
handleSteering(dt);
|
||||
handleBraking();
|
||||
}
|
||||
|
||||
AIBaseController::update(dt);
|
||||
|
||||
} // update
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void BattleAI::checkIfStuck(const float dt)
|
||||
{
|
||||
if (m_is_stuck) return;
|
||||
|
||||
if (m_kart->getKartAnimation() || m_world->isStartPhase())
|
||||
{
|
||||
m_on_node.clear();
|
||||
m_time_since_driving = 0.0f;
|
||||
}
|
||||
|
||||
m_on_node.insert(m_world->getKartNode(m_kart->getWorldKartId()));
|
||||
m_time_since_driving += dt;
|
||||
|
||||
if ((m_time_since_driving >=
|
||||
(m_cur_difficulty == RaceManager::DIFFICULTY_EASY ? 2.0f : 1.5f)
|
||||
&& m_on_node.size() < 2 && !m_is_uturn &&
|
||||
fabsf(m_kart->getSpeed()) < 3.0f) || isStuck() == true)
|
||||
{
|
||||
// Check whether a kart stay on the same node for a period of time
|
||||
// Or crashed 3 times
|
||||
m_on_node.clear();
|
||||
m_time_since_driving = 0.0f;
|
||||
AIBaseController::reset();
|
||||
m_is_stuck = true;
|
||||
}
|
||||
else if (m_time_since_driving >=
|
||||
(m_cur_difficulty == RaceManager::DIFFICULTY_EASY ? 2.0f : 1.5f))
|
||||
{
|
||||
m_on_node.clear(); // Reset for any correct movement
|
||||
m_time_since_driving = 0.0f;
|
||||
}
|
||||
|
||||
} // checkIfStuck
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void BattleAI::checkPosition(const Vec3 &point, posData *pos_data)
|
||||
{
|
||||
// Convert to local coordinates from the point of view of current kart
|
||||
btQuaternion q(btVector3(0, 1, 0), -m_kart->getHeading());
|
||||
Vec3 p = point - m_kart->getXYZ();
|
||||
Vec3 local_coordinates = quatRotate(q, p);
|
||||
|
||||
// on_side: tell whether it's left or right hand side
|
||||
if (local_coordinates.getX() < 0)
|
||||
pos_data->on_side = true;
|
||||
else
|
||||
pos_data->on_side = false;
|
||||
|
||||
// behind: tell whether it's behind or not
|
||||
if (local_coordinates.getZ() < 0)
|
||||
pos_data->behind = true;
|
||||
else
|
||||
pos_data->behind = false;
|
||||
|
||||
pos_data->angle = atan2(fabsf(local_coordinates.getX()),
|
||||
fabsf(local_coordinates.getZ()));
|
||||
pos_data->distance = p.length_2d();
|
||||
} // checkPosition
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void BattleAI::findClosestKart(bool difficulty)
|
||||
{
|
||||
float distance = 99999.9f;
|
||||
const unsigned int n = m_world->getNumKarts();
|
||||
int closest_kart_num = 0;
|
||||
|
||||
for (unsigned int i = 0; i < n; i++)
|
||||
{
|
||||
const AbstractKart* kart = m_world->getKart(i);
|
||||
if (kart->isEliminated()) continue;
|
||||
|
||||
if (kart->getWorldKartId() == m_kart->getWorldKartId())
|
||||
continue; // Skip the same kart
|
||||
|
||||
// Test whether takes current difficulty into account for closest kart
|
||||
// Notice: it don't affect aiming, this function will be called once
|
||||
// more in handleItems, which ignore difficulty.
|
||||
if (m_cur_difficulty == RaceManager::DIFFICULTY_EASY && difficulty)
|
||||
{
|
||||
// Skip human players for novice mode unless only human players left
|
||||
const AbstractKart* temp = m_world->getKart(i);
|
||||
if (temp->getController()->isPlayerController() &&
|
||||
(m_world->getCurrentNumKarts() -
|
||||
m_world->getCurrentNumPlayers()) > 1)
|
||||
continue;
|
||||
}
|
||||
else if (m_cur_difficulty == RaceManager::DIFFICULTY_BEST && difficulty)
|
||||
{
|
||||
// Skip AI players for supertux mode
|
||||
const AbstractKart* temp = m_world->getKart(i);
|
||||
if (!(temp->getController()->isPlayerController()))
|
||||
continue;
|
||||
}
|
||||
|
||||
Vec3 d = kart->getXYZ() - m_kart->getXYZ();
|
||||
if (d.length_2d() <= distance)
|
||||
{
|
||||
distance = d.length_2d();
|
||||
closest_kart_num = i;
|
||||
}
|
||||
}
|
||||
|
||||
const AbstractKart* closest_kart = m_world->getKart(closest_kart_num);
|
||||
m_closest_kart_node = m_world->getKartNode(closest_kart_num);
|
||||
m_closest_kart_point = closest_kart->getXYZ();
|
||||
|
||||
if (!difficulty)
|
||||
{
|
||||
m_closest_kart = m_world->getKart(closest_kart_num);
|
||||
checkPosition(m_closest_kart_point, &m_closest_kart_pos_data);
|
||||
}
|
||||
} // findClosestKart
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void BattleAI::findTarget()
|
||||
{
|
||||
// Find a suitable target to drive to, either powerup or kart
|
||||
if (m_kart->getPowerup()->getType() == PowerupManager::POWERUP_NOTHING &&
|
||||
m_kart->getAttachment()->getType() != Attachment::ATTACH_SWATTER)
|
||||
handleItemCollection(&m_target_point , &m_target_node);
|
||||
else
|
||||
{
|
||||
m_target_point = m_closest_kart_point;
|
||||
m_target_node = m_closest_kart_node;
|
||||
}
|
||||
} // findTarget
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Handles acceleration.
|
||||
* \param dt Time step size.
|
||||
*/
|
||||
void BattleAI::handleAcceleration(const float dt)
|
||||
{
|
||||
if (m_controls->m_brake)
|
||||
{
|
||||
m_controls->m_accel = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
const float handicap =
|
||||
(m_cur_difficulty == RaceManager::DIFFICULTY_EASY ? 0.7f : 1.0f);
|
||||
m_controls->m_accel = stk_config->m_ai_acceleration * handicap;
|
||||
|
||||
} // handleAcceleration
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void BattleAI::handleUTurn(const float dt)
|
||||
{
|
||||
const float turn_side = (m_adjusting_side ? 1.0f : -1.0f);
|
||||
|
||||
if (fabsf(m_kart->getSpeed()) >
|
||||
(m_kart->getKartProperties()->getEngineMaxSpeed() / 5)
|
||||
&& m_kart->getSpeed() < 0) // Try to emulate reverse like human players
|
||||
m_controls->m_accel = -0.06f;
|
||||
else
|
||||
m_controls->m_accel = -5.0f;
|
||||
|
||||
if (m_time_since_uturn >=
|
||||
(m_cur_difficulty == RaceManager::DIFFICULTY_EASY ? 2.0f : 1.5f))
|
||||
setSteering(-(turn_side), dt); // Preventing keep going around circle
|
||||
else
|
||||
setSteering(turn_side, dt);
|
||||
m_time_since_uturn += dt;
|
||||
|
||||
checkPosition(m_target_point, &m_cur_kart_pos_data);
|
||||
if (!m_cur_kart_pos_data.behind || m_time_since_uturn >
|
||||
(m_cur_difficulty == RaceManager::DIFFICULTY_EASY ? 3.5f : 3.0f))
|
||||
{
|
||||
m_is_uturn = false;
|
||||
m_time_since_uturn = 0.0f;
|
||||
}
|
||||
else
|
||||
m_is_uturn = true;
|
||||
} // handleUTurn
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** This function sets the steering.
|
||||
* \param dt Time step size.
|
||||
*/
|
||||
void BattleAI::handleSteering(const float dt)
|
||||
{
|
||||
const int current_node = m_world->getKartNode(m_kart->getWorldKartId());
|
||||
|
||||
if (current_node == BattleGraph::UNKNOWN_POLY ||
|
||||
m_target_node == BattleGraph::UNKNOWN_POLY) return;
|
||||
|
||||
if (m_is_steering_overridden)
|
||||
{
|
||||
// Steering is overridden to avoid eating banana
|
||||
const float turn_side = (m_adjusting_side ? 1.0f : -1.0f);
|
||||
m_time_since_steering_overridden += dt;
|
||||
if (m_time_since_steering_overridden > 0.35f)
|
||||
setSteering(-(turn_side), dt);
|
||||
else
|
||||
setSteering(turn_side, dt);
|
||||
if (m_time_since_steering_overridden > 0.7f)
|
||||
{
|
||||
m_is_steering_overridden = false;
|
||||
m_time_since_steering_overridden = 0.0f;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_target_node == current_node)
|
||||
{
|
||||
// Very close to the item, steer directly
|
||||
checkPosition(m_target_point, &m_cur_kart_pos_data);
|
||||
#ifdef AI_DEBUG
|
||||
m_debug_sphere->setPosition(m_target_point.toIrrVector());
|
||||
#endif
|
||||
if (m_cur_kart_pos_data.behind)
|
||||
{
|
||||
m_adjusting_side = m_cur_kart_pos_data.on_side;
|
||||
m_is_uturn = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
float target_angle = steerToPoint(m_target_point);
|
||||
setSteering(target_angle, dt);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
else if (m_target_node != current_node)
|
||||
{
|
||||
findPortals(current_node, m_target_node);
|
||||
stringPull(m_kart->getXYZ(), m_target_point);
|
||||
if (m_path_corners.size() > 0)
|
||||
m_target_point = m_path_corners[0];
|
||||
|
||||
checkPosition(m_target_point, &m_cur_kart_pos_data);
|
||||
#ifdef AI_DEBUG
|
||||
m_debug_sphere->setPosition(m_target_point.toIrrVector());
|
||||
#endif
|
||||
if (m_cur_kart_pos_data.behind)
|
||||
{
|
||||
m_adjusting_side = m_cur_kart_pos_data.on_side;
|
||||
m_is_uturn = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
float target_angle = steerToPoint(m_target_point);
|
||||
setSteering(target_angle, dt);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
// Do nothing (go straight) if no targets found
|
||||
setSteering(0.0f, dt);
|
||||
return;
|
||||
}
|
||||
} // handleSteering
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void BattleAI::handleBanana()
|
||||
{
|
||||
if (m_is_steering_overridden || m_is_uturn) return;
|
||||
|
||||
const std::vector< std::pair<const Item*, int> >& item_list =
|
||||
BattleGraph::get()->getItemList();
|
||||
const unsigned int items_count = item_list.size();
|
||||
for (unsigned int i = 0; i < items_count; ++i)
|
||||
{
|
||||
const Item* item = item_list[i].first;
|
||||
if (item->getType() == Item::ITEM_BANANA && !item->wasCollected())
|
||||
{
|
||||
posData banana_pos = {0};
|
||||
checkPosition(item->getXYZ(), &banana_pos);
|
||||
if (banana_pos.angle < 0.2f && banana_pos.distance < 7.5f &&
|
||||
!banana_pos.behind)
|
||||
{
|
||||
// Check whether it's straight ahead towards a banana
|
||||
// If so, try to do hard turn to avoid
|
||||
m_adjusting_side = banana_pos.on_side;
|
||||
m_is_steering_overridden = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // handleBanana
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** This function finds the polyon edges(portals) that the AI will cross before
|
||||
* reaching its destination. We start from the current polygon and call
|
||||
* BattleGraph::getNextShortestPathPoly() to find the next polygon on the shortest
|
||||
* path to the destination. Then find the common edge between the current
|
||||
* poly and the next poly, store it and step through the channel.
|
||||
*
|
||||
* 1----2----3 In this case, the portals are:
|
||||
* |strt| | (2,5) (4,5) (10,7) (10,9) (11,12)
|
||||
* 6----5----4
|
||||
* | |
|
||||
* 7----10----11----14
|
||||
* | | | end |
|
||||
* 8----9-----12----13
|
||||
*
|
||||
* \param start The start node(polygon) of the channel.
|
||||
* \param end The end node(polygon) of the channel.
|
||||
*/
|
||||
void BattleAI::findPortals(int start, int end)
|
||||
{
|
||||
int this_node = start;
|
||||
|
||||
// We can't use NULL because NULL==0 which is a valid node, so we initialize
|
||||
// with a value that is always invalid.
|
||||
int next_node = -999;
|
||||
|
||||
m_portals.clear();
|
||||
|
||||
while (next_node != end && this_node != -1 && next_node != -1 && this_node != end)
|
||||
{
|
||||
next_node = BattleGraph::get()->getNextShortestPathPoly(this_node, end);
|
||||
if (next_node == BattleGraph::UNKNOWN_POLY || next_node == -999) return;
|
||||
|
||||
std::vector<int> this_node_verts =
|
||||
NavMesh::get()->getNavPoly(this_node).getVerticesIndex();
|
||||
std::vector<int> next_node_verts=
|
||||
NavMesh::get()->getNavPoly(next_node).getVerticesIndex();
|
||||
|
||||
// this_node_verts and next_node_verts hold vertices of polygons in CCW order
|
||||
// We reverse next_node_verts so it becomes easy to compare edges in the next step
|
||||
std::reverse(next_node_verts.begin(),next_node_verts.end());
|
||||
|
||||
Vec3 portalLeft, portalRight;
|
||||
//bool flag = 0;
|
||||
for (unsigned int n_i = 0; n_i < next_node_verts.size(); n_i++)
|
||||
{
|
||||
for (unsigned int t_i = 0; t_i < this_node_verts.size(); t_i++)
|
||||
{
|
||||
if ((next_node_verts[n_i] == this_node_verts[t_i]) &&
|
||||
(next_node_verts[(n_i+1)%next_node_verts.size()] ==
|
||||
this_node_verts[(t_i+1)%this_node_verts.size()]))
|
||||
{
|
||||
portalLeft = NavMesh::get()->
|
||||
getVertex(this_node_verts[(t_i+1)%this_node_verts.size()]);
|
||||
|
||||
portalRight = NavMesh::get()->getVertex(this_node_verts[t_i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_portals.push_back(std::make_pair(portalLeft, portalRight));
|
||||
// for debugging:
|
||||
//m_debug_sphere->setPosition((portalLeft).toIrrVector());
|
||||
this_node = next_node;
|
||||
}
|
||||
} // findPortals
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** This function implements the funnel algorithm for finding shortest paths
|
||||
* through a polygon channel. This means that we should move from corner to
|
||||
* corner to move on the most straight and shortest path to the destination.
|
||||
* This can be visualized as pulling a string from the end point to the start.
|
||||
* The string will bend at the corners, and this algorithm will find those
|
||||
* corners using portals from findPortals(). The AI will aim at the first
|
||||
* corner and the rest can be used for estimating the curve (braking).
|
||||
*
|
||||
* 1----2----3 In this case, the corners are:
|
||||
* |strt| | <5,10,end>
|
||||
* 6----5----4
|
||||
* | |
|
||||
* 7----10----11----14
|
||||
* | | | end |
|
||||
* 8----9-----12----13
|
||||
*
|
||||
* \param start_pos The start position (usually the AI's current position).
|
||||
* \param end_pos The end position (m_target_point).
|
||||
*/
|
||||
void BattleAI::stringPull(const Vec3& start_pos, const Vec3& end_pos)
|
||||
{
|
||||
Vec3 funnel_apex = start_pos;
|
||||
Vec3 funnel_left = m_portals[0].first;
|
||||
Vec3 funnel_right = m_portals[0].second;
|
||||
unsigned int apex_index=0, fun_left_index=0, fun_right_index=0;
|
||||
m_portals.push_back(std::make_pair(end_pos, end_pos));
|
||||
m_path_corners.clear();
|
||||
const float eps=0.0001f;
|
||||
|
||||
for (unsigned int i = 0; i < m_portals.size(); i++)
|
||||
{
|
||||
Vec3 portal_left = m_portals[i].first;
|
||||
Vec3 portal_right = m_portals[i].second;
|
||||
|
||||
//Compute for left edge
|
||||
if ((funnel_left == funnel_apex) ||
|
||||
portal_left.sideOfLine2D(funnel_apex, funnel_left) <= -eps)
|
||||
{
|
||||
funnel_left = 0.98f*portal_left + 0.02f*portal_right;
|
||||
//funnel_left = portal_left;
|
||||
fun_left_index = i;
|
||||
|
||||
if (portal_left.sideOfLine2D(funnel_apex, funnel_right) < -eps)
|
||||
{
|
||||
funnel_apex = funnel_right;
|
||||
apex_index = fun_right_index;
|
||||
m_path_corners.push_back(funnel_apex);
|
||||
|
||||
funnel_left = funnel_apex;
|
||||
funnel_right = funnel_apex;
|
||||
i = apex_index;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
//Compute for right edge
|
||||
if ((funnel_right == funnel_apex) ||
|
||||
portal_right.sideOfLine2D(funnel_apex, funnel_right) >= eps)
|
||||
{
|
||||
funnel_right = 0.98f*portal_right + 0.02f*portal_left;
|
||||
//funnel_right = portal_right;
|
||||
fun_right_index = i;
|
||||
|
||||
if (portal_right.sideOfLine2D(funnel_apex, funnel_left) > eps)
|
||||
{
|
||||
funnel_apex = funnel_left;
|
||||
apex_index = fun_left_index;
|
||||
m_path_corners.push_back(funnel_apex);
|
||||
|
||||
funnel_left = funnel_apex;
|
||||
funnel_right = funnel_apex;
|
||||
i = apex_index;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Push end_pos to m_path_corners so if no corners, we aim at target
|
||||
m_path_corners.push_back(end_pos);
|
||||
} // stringPull
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** This function handles braking. It calls determineTurnRadius() to find out
|
||||
* the curve radius. Depending on the turn radius, it finds out the maximum
|
||||
* speed. If the current speed is greater than the max speed and a set minimum
|
||||
* speed, brakes are applied.
|
||||
*/
|
||||
void BattleAI::handleBraking()
|
||||
{
|
||||
m_controls->m_brake = false;
|
||||
|
||||
if (m_world->getKartNode(m_kart->getWorldKartId())
|
||||
== BattleGraph::UNKNOWN_POLY ||
|
||||
m_target_node == BattleGraph::UNKNOWN_POLY ||
|
||||
m_is_steering_overridden) return;
|
||||
|
||||
// A kart will not brake when the speed is already slower than this
|
||||
// value. This prevents a kart from going too slow (or even backwards)
|
||||
// in tight curves.
|
||||
const float MIN_SPEED = 5.0f;
|
||||
|
||||
std::vector<Vec3> points;
|
||||
|
||||
points.push_back(m_kart->getXYZ());
|
||||
points.push_back(m_path_corners[0]);
|
||||
points.push_back((m_path_corners.size()>=2) ? m_path_corners[1] : m_path_corners[0]);
|
||||
|
||||
float current_curve_radius = BattleAI::determineTurnRadius(points);
|
||||
|
||||
Vec3 d1 = m_kart->getXYZ() - m_target_point;
|
||||
Vec3 d2 = m_kart->getXYZ() - m_path_corners[0];
|
||||
if (d1.length2_2d() < d2.length2_2d())
|
||||
current_curve_radius = d1.length_2d();
|
||||
|
||||
float max_turn_speed = m_kart->getSpeedForTurnRadius(current_curve_radius);
|
||||
|
||||
if (m_kart->getSpeed() > max_turn_speed &&
|
||||
m_kart->getSpeed() > MIN_SPEED)
|
||||
{
|
||||
m_controls->m_brake = true;
|
||||
}
|
||||
|
||||
} // handleBraking
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** The turn radius is determined by fitting a parabola to 3 points: current
|
||||
* location of AI, first corner and the second corner. Once the constants are
|
||||
* computed, a formula is used to find the radius of curvature at the kart's
|
||||
* current location.
|
||||
* NOTE: This method does not apply enough braking, should think of something
|
||||
* else.
|
||||
*/
|
||||
float BattleAI::determineTurnRadius( std::vector<Vec3>& points )
|
||||
{
|
||||
// Declaring variables
|
||||
float a, b;
|
||||
irr::core::CMatrix4<float> A;
|
||||
irr::core::CMatrix4<float> X;
|
||||
irr::core::CMatrix4<float> B;
|
||||
|
||||
//Populating matrices
|
||||
for (unsigned int i = 0; i < 3; i++)
|
||||
{
|
||||
A(i, 0) = points[i].x()*points[i].x();
|
||||
A(i, 1) = points[i].x();
|
||||
A(i, 2) = 1.0f;
|
||||
A(i, 3) = 0.0f;
|
||||
}
|
||||
A(3, 0) = A(3, 1) = A(3, 2) = 0.0f;
|
||||
A(3, 3) = 1.0f;
|
||||
|
||||
for (unsigned int i = 0; i < 3; i++)
|
||||
{
|
||||
B(i, 0) = points[i].z();
|
||||
B(i, 1) = 0.0f;
|
||||
B(i, 2) = 0.0f;
|
||||
B(i, 3) = 0.0f;
|
||||
}
|
||||
B(3, 0) = B(3, 1) = B(3, 2) = B(3, 3) = 0.0f;
|
||||
|
||||
//Computing inverse : X = inv(A)*B
|
||||
irr::core::CMatrix4<float> invA;
|
||||
if (!A.getInverse(invA))
|
||||
return -1;
|
||||
|
||||
X = invA*B;
|
||||
a = X(0, 0);
|
||||
b = X(0, 1);
|
||||
//c = X(0, 2);
|
||||
|
||||
float x = points.front().x();
|
||||
//float z = a*pow(x, 2) + b*x + c;
|
||||
float dx_by_dz = 2*a*x + b;
|
||||
float d2x_by_dz = 2*a;
|
||||
|
||||
float radius = pow(abs(1 + pow(dx_by_dz, 2)), 1.5f)/ abs(d2x_by_dz);
|
||||
|
||||
return radius;
|
||||
} // determineTurnRadius
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void BattleAI::handleItems(const float dt)
|
||||
{
|
||||
m_controls->m_fire = false;
|
||||
if (m_kart->getKartAnimation() ||
|
||||
m_kart->getPowerup()->getType() == PowerupManager::POWERUP_NOTHING)
|
||||
return;
|
||||
|
||||
// Find a closest kart again, this time we ignore difficulty
|
||||
findClosestKart(false);
|
||||
|
||||
if (!m_closest_kart) return;
|
||||
|
||||
m_time_since_last_shot += dt;
|
||||
|
||||
float min_bubble_time = 2.0f;
|
||||
const bool difficulty = m_cur_difficulty == RaceManager::DIFFICULTY_EASY ||
|
||||
m_cur_difficulty == RaceManager::DIFFICULTY_MEDIUM;
|
||||
|
||||
const bool fire_behind = m_closest_kart_pos_data.behind && !difficulty;
|
||||
|
||||
const bool perfect_aim = m_closest_kart_pos_data.angle < 0.2f;
|
||||
|
||||
switch(m_kart->getPowerup()->getType())
|
||||
{
|
||||
case PowerupManager::POWERUP_BUBBLEGUM:
|
||||
{
|
||||
Attachment::AttachmentType type = m_kart->getAttachment()->getType();
|
||||
// Don't use shield when we have a swatter.
|
||||
if (type == Attachment::ATTACH_SWATTER ||
|
||||
type == Attachment::ATTACH_NOLOKS_SWATTER)
|
||||
break;
|
||||
|
||||
// Check if a flyable (cake, ...) is close. If so, use bubblegum
|
||||
// as shield
|
||||
if (!m_kart->isShielded() &&
|
||||
projectile_manager->projectileIsClose(m_kart,
|
||||
m_ai_properties->m_shield_incoming_radius))
|
||||
{
|
||||
m_controls->m_fire = true;
|
||||
m_controls->m_look_back = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// Avoid dropping all bubble gums one after another
|
||||
if (m_time_since_last_shot < 3.0f) break;
|
||||
|
||||
// Use bubblegum if the next kart behind is 'close' but not too close,
|
||||
// or can't find a close kart for too long time
|
||||
if ((m_closest_kart_pos_data.distance < 15.0f &&
|
||||
m_closest_kart_pos_data.distance > 3.0f) ||
|
||||
m_time_since_last_shot > 15.0f)
|
||||
{
|
||||
m_controls->m_fire = true;
|
||||
m_controls->m_look_back = true;
|
||||
break;
|
||||
}
|
||||
|
||||
break; // POWERUP_BUBBLEGUM
|
||||
}
|
||||
case PowerupManager::POWERUP_CAKE:
|
||||
{
|
||||
// if the kart has a shield, do not break it by using a cake.
|
||||
if (m_kart->getShieldTime() > min_bubble_time)
|
||||
break;
|
||||
|
||||
// Leave some time between shots
|
||||
if (m_time_since_last_shot < 1.0f) break;
|
||||
|
||||
if (m_closest_kart_pos_data.distance < 25.0f &&
|
||||
!m_closest_kart->isInvulnerable())
|
||||
{
|
||||
m_controls->m_fire = true;
|
||||
m_controls->m_look_back = fire_behind;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
} // POWERUP_CAKE
|
||||
|
||||
case PowerupManager::POWERUP_BOWLING:
|
||||
{
|
||||
// if the kart has a shield, do not break it by using a bowling ball.
|
||||
if (m_kart->getShieldTime() > min_bubble_time)
|
||||
break;
|
||||
|
||||
// Leave some time between shots
|
||||
if (m_time_since_last_shot < 1.0f) break;
|
||||
|
||||
if (m_closest_kart_pos_data.distance < 6.0f &&
|
||||
(difficulty || perfect_aim))
|
||||
{
|
||||
m_controls->m_fire = true;
|
||||
m_controls->m_look_back = fire_behind;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
} // POWERUP_BOWLING
|
||||
|
||||
case PowerupManager::POWERUP_SWATTER:
|
||||
{
|
||||
// Squared distance for which the swatter works
|
||||
float d2 = m_kart->getKartProperties()->getSwatterDistance();
|
||||
// if the kart has a shield, do not break it by using a swatter.
|
||||
if (m_kart->getShieldTime() > min_bubble_time)
|
||||
break;
|
||||
|
||||
if (!m_closest_kart->isSquashed() &&
|
||||
m_closest_kart_pos_data.distance < d2 &&
|
||||
m_closest_kart->getSpeed() < m_kart->getSpeed())
|
||||
{
|
||||
m_controls->m_fire = true;
|
||||
m_controls->m_look_back = false;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Below powerups won't appear in battle mode, so skip them
|
||||
case PowerupManager::POWERUP_ZIPPER:
|
||||
break; // POWERUP_ZIPPER
|
||||
|
||||
case PowerupManager::POWERUP_PLUNGER:
|
||||
break; // POWERUP_PLUNGER
|
||||
|
||||
case PowerupManager::POWERUP_SWITCH: // Don't handle switch
|
||||
m_controls->m_fire = true; // (use it no matter what) for now
|
||||
break; // POWERUP_SWITCH
|
||||
|
||||
case PowerupManager::POWERUP_PARACHUTE:
|
||||
break; // POWERUP_PARACHUTE
|
||||
|
||||
case PowerupManager::POWERUP_ANVIL:
|
||||
break; // POWERUP_ANVIL
|
||||
|
||||
case PowerupManager::POWERUP_RUBBERBALL:
|
||||
break;
|
||||
|
||||
default:
|
||||
Log::error("BattleAI",
|
||||
"Invalid or unhandled powerup '%d' in default AI.",
|
||||
m_kart->getPowerup()->getType());
|
||||
assert(false);
|
||||
}
|
||||
if (m_controls->m_fire)
|
||||
m_time_since_last_shot = 0.0f;
|
||||
} // handleItems
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void BattleAI::handleItemCollection(Vec3* aim_point, int* target_node)
|
||||
{
|
||||
float distance = 99999.9f;
|
||||
const std::vector< std::pair<const Item*, int> >& item_list =
|
||||
BattleGraph::get()->getItemList();
|
||||
const unsigned int items_count = item_list.size();
|
||||
|
||||
if (item_list.empty())
|
||||
{
|
||||
// Notice: this should not happen, as it makes no sense
|
||||
// for an arean without items, if so how can attack happen?
|
||||
Log::fatal ("BattleAI",
|
||||
"AI can't find any items in the arena, "
|
||||
"maybe there is something wrong with the navmesh, "
|
||||
"make sure it lies closely to the ground.");
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int closest_item_num = 0;
|
||||
|
||||
for (unsigned int i = 0; i < items_count; ++i)
|
||||
{
|
||||
const Item* item = item_list[i].first;
|
||||
|
||||
if (item->wasCollected()) continue;
|
||||
|
||||
if ((item->getType() == Item::ITEM_NITRO_BIG ||
|
||||
item->getType() == Item::ITEM_NITRO_SMALL) &&
|
||||
(m_kart->getEnergy() >
|
||||
m_kart->getKartProperties()->getNitroSmallContainer()))
|
||||
continue; // Ignore nitro when already has some
|
||||
|
||||
Vec3 d = item->getXYZ() - m_kart->getXYZ();
|
||||
if (d.length_2d() <= distance &&
|
||||
(item->getType() == Item::ITEM_BONUS_BOX ||
|
||||
item->getType() == Item::ITEM_NITRO_BIG ||
|
||||
item->getType() == Item::ITEM_NITRO_SMALL))
|
||||
{
|
||||
closest_item_num = i;
|
||||
distance = d.length_2d();
|
||||
}
|
||||
}
|
||||
|
||||
const Item *item_selected = item_list[closest_item_num].first;
|
||||
if (item_selected->getType() == Item::ITEM_BONUS_BOX ||
|
||||
item_selected->getType() == Item::ITEM_NITRO_BIG ||
|
||||
item_selected->getType() == Item::ITEM_NITRO_SMALL)
|
||||
{
|
||||
*aim_point = item_selected->getXYZ();
|
||||
*target_node = item_list[closest_item_num].second;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Handle when all targets are swapped, which make AIs follow karts
|
||||
*aim_point = m_closest_kart_point;
|
||||
*target_node = m_closest_kart_node;
|
||||
}
|
||||
} // handleItemCollection
|
160
src/karts/controller/battle_ai.hpp
Normal file
160
src/karts/controller/battle_ai.hpp
Normal file
@ -0,0 +1,160 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2004-2005 Steve Baker <sjbaker1@airmail.net>
|
||||
// Copyright (C) 2006-2007 Eduardo Hernandez Munoz
|
||||
// Copyright (C) 2010-2015 Joerg Henrichs
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#ifndef HEADER_BATTLE_AI_HPP
|
||||
#define HEADER_BATTLE_AI_HPP
|
||||
|
||||
#undef AI_DEBUG
|
||||
#ifdef AI_DEBUG
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#endif
|
||||
|
||||
#include "karts/controller/ai_base_controller.hpp"
|
||||
#include "race/race_manager.hpp"
|
||||
#include "utils/random_generator.hpp"
|
||||
|
||||
class ThreeStrikesBattle;
|
||||
class Vec3;
|
||||
class Item;
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace scene { class ISceneNode; }
|
||||
namespace video { class ITexture; }
|
||||
}
|
||||
|
||||
class BattleAI : public AIBaseController
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
/** Holds the position info of targets. */
|
||||
struct posData {bool behind; bool on_side; float angle; float distance;};
|
||||
|
||||
/** Used by handleBanana and UTurn, it tells whether to do left or right
|
||||
* turning when steering is overridden. */
|
||||
bool m_adjusting_side;
|
||||
|
||||
int m_closest_kart_node;
|
||||
Vec3 m_closest_kart_point;
|
||||
|
||||
/** Pointer to the closest kart around this kart. */
|
||||
AbstractKart *m_closest_kart;
|
||||
|
||||
posData m_closest_kart_pos_data;
|
||||
posData m_cur_kart_pos_data;
|
||||
|
||||
/** Holds the current difficulty. */
|
||||
RaceManager::Difficulty m_cur_difficulty;
|
||||
|
||||
/** Indicates that the steering of kart is overridden, and
|
||||
* m_time_since_steering_overridden is counting down. */
|
||||
bool m_is_steering_overridden;
|
||||
|
||||
/** Indicates that the kart is currently stuck, and m_time_since_reversing is
|
||||
* counting down. */
|
||||
bool m_is_stuck;
|
||||
|
||||
/** Indicates that the kart need a uturn to reach a node behind, and
|
||||
* m_time_since_uturn is counting down. */
|
||||
bool m_is_uturn;
|
||||
|
||||
/** Holds the unique node ai has driven through, useful to tell if AI is
|
||||
* stuck by determine the size of this set. */
|
||||
std::set <int> m_on_node;
|
||||
|
||||
/** Holds the corner points computed using the funnel algorithm that the AI
|
||||
* will eventaully move through. See stringPull(). */
|
||||
std::vector<Vec3> m_path_corners;
|
||||
|
||||
/** Holds the set of portals that the kart will cross when moving through
|
||||
* polygon channel. See findPortals(). */
|
||||
std::vector<std::pair<Vec3,Vec3> > m_portals;
|
||||
|
||||
/** The node(poly) at which the target point lies in. */
|
||||
int m_target_node;
|
||||
|
||||
/** The target point. */
|
||||
Vec3 m_target_point;
|
||||
|
||||
/** Time an item has been collected and not used. */
|
||||
float m_time_since_last_shot;
|
||||
|
||||
/** This is a timer that counts down when the kart is reversing to get unstuck. */
|
||||
float m_time_since_reversing;
|
||||
|
||||
/** This is a timer that counts down when the kart is starting to drive. */
|
||||
float m_time_since_driving;
|
||||
|
||||
/** This is a timer that counts down when the steering of kart is overridden. */
|
||||
float m_time_since_steering_overridden;
|
||||
|
||||
/** This is a timer that counts down when the kart is doing u-turn. */
|
||||
float m_time_since_uturn;
|
||||
|
||||
void checkIfStuck(const float dt);
|
||||
void checkPosition(const Vec3 &, posData*);
|
||||
float determineTurnRadius(std::vector<Vec3>& points);
|
||||
void findClosestKart(bool difficulty);
|
||||
void findPortals(int start, int end);
|
||||
void findTarget();
|
||||
void handleAcceleration(const float dt);
|
||||
void handleBanana();
|
||||
void handleBraking();
|
||||
void handleItems(const float dt);
|
||||
void handleItemCollection(Vec3*, int*);
|
||||
void handleSteering(const float dt);
|
||||
void handleSwatter();
|
||||
void handleUTurn(const float dt);
|
||||
void stringPull(const Vec3&, const Vec3&);
|
||||
|
||||
protected:
|
||||
|
||||
/** Keep a pointer to world. */
|
||||
ThreeStrikesBattle *m_world;
|
||||
|
||||
#ifdef AI_DEBUG
|
||||
/** For debugging purpose: a sphere indicating where the AI
|
||||
* is targeting at. */
|
||||
irr::scene::ISceneNode *m_debug_sphere;
|
||||
#endif
|
||||
|
||||
public:
|
||||
BattleAI(AbstractKart *kart,
|
||||
StateManager::ActivePlayer *player=NULL);
|
||||
~BattleAI();
|
||||
virtual void update (float delta);
|
||||
virtual void reset ();
|
||||
|
||||
virtual void crashed(const AbstractKart *k) {};
|
||||
virtual void handleZipper(bool play_sound) {};
|
||||
virtual void finishedRace(float time) {};
|
||||
virtual void collectedItem(const Item &item, int add_info=-1,
|
||||
float previous_energy=0) {};
|
||||
virtual void setPosition(int p) {};
|
||||
virtual bool isNetworkController() const { return false; }
|
||||
virtual bool isPlayerController() const { return false; }
|
||||
virtual void action(PlayerAction action, int value) {};
|
||||
virtual void skidBonusTriggered() {};
|
||||
virtual bool disableSlipstreamBonus() const {return 0; }
|
||||
virtual void newLap(int lap) {};
|
||||
};
|
||||
|
||||
#endif
|
@ -57,6 +57,7 @@ protected:
|
||||
|
||||
/** The name of the controller, mainly used for debugging purposes. */
|
||||
std::string m_controller_name;
|
||||
|
||||
public:
|
||||
Controller (AbstractKart *kart,
|
||||
StateManager::ActivePlayer *player=NULL);
|
||||
|
@ -52,13 +52,13 @@
|
||||
|
||||
EndController::EndController(AbstractKart *kart, StateManager::ActivePlayer *player,
|
||||
Controller *prev_controller)
|
||||
: AIBaseController(kart, player)
|
||||
: AIBaseLapController(kart, player)
|
||||
{
|
||||
m_previous_controller = prev_controller;
|
||||
if(race_manager->getMinorMode()!=RaceManager::MINOR_MODE_3_STRIKES &&
|
||||
race_manager->getMinorMode()!=RaceManager::MINOR_MODE_SOCCER)
|
||||
{
|
||||
// Overwrite the random selected default path from AIBaseController
|
||||
// Overwrite the random selected default path from AIBaseLapController
|
||||
// with a path that always picks the first branch (i.e. it follows
|
||||
// the main driveline).
|
||||
std::vector<unsigned int> next;
|
||||
@ -124,7 +124,7 @@ EndController::~EndController()
|
||||
//-----------------------------------------------------------------------------
|
||||
void EndController::reset()
|
||||
{
|
||||
AIBaseController::reset();
|
||||
AIBaseLapController::reset();
|
||||
|
||||
m_crash_time = 0.0f;
|
||||
m_time_since_stuck = 0.0f;
|
||||
@ -179,7 +179,7 @@ void EndController::update(float dt)
|
||||
m_controls->m_brake = false;
|
||||
m_controls->m_accel = 1.0f;
|
||||
|
||||
AIBaseController::update(dt);
|
||||
AIBaseLapController::update(dt);
|
||||
|
||||
// In case of battle mode: don't do anything
|
||||
if(race_manager->getMinorMode()==RaceManager::MINOR_MODE_3_STRIKES ||
|
||||
|
@ -21,7 +21,7 @@
|
||||
#ifndef HEADER_END_CONTROLLER_HPP
|
||||
#define HEADER_END_CONTROLLER_HPP
|
||||
|
||||
#include "karts/controller/ai_base_controller.hpp"
|
||||
#include "karts/controller/ai_base_lap_controller.hpp"
|
||||
|
||||
class Camera;
|
||||
class LinearWorld;
|
||||
@ -40,7 +40,7 @@ namespace irr
|
||||
/**
|
||||
* \ingroup controller
|
||||
*/
|
||||
class EndController : public AIBaseController
|
||||
class EndController : public AIBaseLapController
|
||||
{
|
||||
private:
|
||||
/** Stores the type of the previous controller. This is necessary so that
|
||||
|
@ -197,7 +197,7 @@ void NetworkPlayerController::steer(float dt, int steer_val)
|
||||
// change speed is used.
|
||||
const float STEER_CHANGE = ( (steer_val<=0 && m_controls->m_steer<0) ||
|
||||
(steer_val>=0 && m_controls->m_steer>0) )
|
||||
? dt/m_kart->getKartProperties()->getTimeResetSteer()
|
||||
? dt/m_kart->getKartProperties()->getTurnTimeResetSteer()
|
||||
: dt/m_kart->getTimeFullSteer(fabsf(m_controls->m_steer));
|
||||
if (steer_val < 0)
|
||||
{
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "network/network_world.hpp"
|
||||
#include "race/history.hpp"
|
||||
#include "states_screens/race_gui_base.hpp"
|
||||
#include "tracks/battle_graph.hpp"
|
||||
#include "utils/constants.hpp"
|
||||
#include "utils/log.hpp"
|
||||
#include "utils/translation.hpp"
|
||||
@ -254,7 +255,7 @@ void PlayerController::steer(float dt, int steer_val)
|
||||
// change speed is used.
|
||||
const float STEER_CHANGE = ( (steer_val<=0 && m_controls->m_steer<0) ||
|
||||
(steer_val>=0 && m_controls->m_steer>0) )
|
||||
? dt/m_kart->getKartProperties()->getTimeResetSteer()
|
||||
? dt/m_kart->getKartProperties()->getTurnTimeResetSteer()
|
||||
: dt/m_kart->getTimeFullSteer(fabsf(m_controls->m_steer));
|
||||
if (steer_val < 0)
|
||||
{
|
||||
|
@ -38,7 +38,6 @@
|
||||
#include "karts/max_speed.hpp"
|
||||
#include "karts/rescue_animation.hpp"
|
||||
#include "karts/skidding.hpp"
|
||||
#include "karts/skidding_properties.hpp"
|
||||
#include "modes/linear_world.hpp"
|
||||
#include "modes/profile_world.hpp"
|
||||
#include "race/race_manager.hpp"
|
||||
@ -60,7 +59,7 @@
|
||||
#include <iostream>
|
||||
|
||||
SkiddingAI::SkiddingAI(AbstractKart *kart)
|
||||
: AIBaseController(kart)
|
||||
: AIBaseLapController(kart)
|
||||
{
|
||||
reset();
|
||||
// Determine if this AI has superpowers, which happens e.g.
|
||||
@ -179,7 +178,7 @@ void SkiddingAI::reset()
|
||||
m_skid_probability_state = SKID_PROBAB_NOT_YET;
|
||||
m_last_item_random = NULL;
|
||||
|
||||
AIBaseController::reset();
|
||||
AIBaseLapController::reset();
|
||||
m_track_node = QuadGraph::UNKNOWN_SECTOR;
|
||||
QuadGraph::get()->findRoadSector(m_kart->getXYZ(), &m_track_node);
|
||||
if(m_track_node==QuadGraph::UNKNOWN_SECTOR)
|
||||
@ -191,7 +190,7 @@ void SkiddingAI::reset()
|
||||
m_track_node = QuadGraph::get()->findOutOfRoadSector(m_kart->getXYZ());
|
||||
}
|
||||
|
||||
AIBaseController::reset();
|
||||
AIBaseLapController::reset();
|
||||
} // reset
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -296,14 +295,14 @@ void SkiddingAI::update(float dt)
|
||||
if(isStuck() && !m_kart->getKartAnimation())
|
||||
{
|
||||
new RescueAnimation(m_kart);
|
||||
AIBaseController::update(dt);
|
||||
AIBaseLapController::update(dt);
|
||||
return;
|
||||
}
|
||||
|
||||
if( m_world->isStartPhase() )
|
||||
{
|
||||
handleRaceStart();
|
||||
AIBaseController::update(dt);
|
||||
AIBaseLapController::update(dt);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -378,7 +377,7 @@ void SkiddingAI::update(float dt)
|
||||
}
|
||||
|
||||
/*And obviously general kart stuff*/
|
||||
AIBaseController::update(dt);
|
||||
AIBaseLapController::update(dt);
|
||||
} // update
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -430,8 +429,7 @@ void SkiddingAI::handleBraking()
|
||||
m_current_track_direction==GraphNode::DIR_RIGHT )
|
||||
{
|
||||
float max_turn_speed =
|
||||
m_kart->getKartProperties()
|
||||
->getSpeedForTurnRadius(m_current_curve_radius);
|
||||
m_kart->getSpeedForTurnRadius(m_current_curve_radius);
|
||||
|
||||
if(m_kart->getSpeed() > 1.5f*max_turn_speed &&
|
||||
m_kart->getSpeed()>MIN_SPEED &&
|
||||
@ -1032,6 +1030,8 @@ void SkiddingAI::evaluateItems(const Item *item, float kart_aim_angle,
|
||||
std::vector<const Item *> *items_to_avoid,
|
||||
std::vector<const Item *> *items_to_collect)
|
||||
{
|
||||
const KartProperties *kp = m_kart->getKartProperties();
|
||||
|
||||
// Ignore items that are currently disabled
|
||||
if(item->getDisableTime()>0) return;
|
||||
|
||||
@ -1052,18 +1052,16 @@ void SkiddingAI::evaluateItems(const Item *item, float kart_aim_angle,
|
||||
// Positive items: try to collect
|
||||
case Item::ITEM_NITRO_BIG:
|
||||
// Only collect nitro, if it can actually be stored.
|
||||
if(m_kart->getEnergy() +
|
||||
m_kart->getKartProperties()->getNitroBigContainer()
|
||||
> m_kart->getKartProperties()->getNitroMax())
|
||||
if (m_kart->getEnergy() + kp->getNitroBigContainer()
|
||||
> kp->getNitroMax())
|
||||
return;
|
||||
// fall through: if we have enough space to store a big
|
||||
// container, we can also store a small container, and
|
||||
// finally fall through to the bonus box code.
|
||||
case Item::ITEM_NITRO_SMALL: avoid = false;
|
||||
// Only collect nitro, if it can actually be stored.
|
||||
if (m_kart->getEnergy() +
|
||||
m_kart->getKartProperties()->getNitroSmallContainer()
|
||||
> m_kart->getKartProperties()->getNitroMax())
|
||||
if (m_kart->getEnergy() + kp->getNitroSmallContainer()
|
||||
> kp->getNitroMax())
|
||||
return;
|
||||
case Item::ITEM_BONUS_BOX:
|
||||
break;
|
||||
@ -1093,7 +1091,7 @@ void SkiddingAI::evaluateItems(const Item *item, float kart_aim_angle,
|
||||
// be if the kart would need to turn sharper, therefore stops
|
||||
// skidding, and will get the bonus speed.
|
||||
bool high_speed = (m_kart->getCurrentMaxSpeed() >
|
||||
m_kart->getKartProperties()->getMaxSpeed() ) ||
|
||||
kp->getEngineMaxSpeed() ) ||
|
||||
m_kart->getSkidding()->getSkidBonusReady();
|
||||
float max_angle = high_speed
|
||||
? m_ai_properties->m_max_item_angle_high_speed
|
||||
@ -1355,13 +1353,13 @@ void SkiddingAI::handleItems(const float dt)
|
||||
|
||||
case PowerupManager::POWERUP_PARACHUTE:
|
||||
// Wait one second more than a previous parachute
|
||||
if(m_time_since_last_shot > stk_config->m_parachute_time_other+1.0f)
|
||||
if(m_time_since_last_shot > m_kart->getKartProperties()->getParachuteDurationOther() + 1.0f)
|
||||
m_controls->m_fire = true;
|
||||
break; // POWERUP_PARACHUTE
|
||||
|
||||
case PowerupManager::POWERUP_ANVIL:
|
||||
// Wait one second more than a previous anvil
|
||||
if(m_time_since_last_shot < stk_config->m_anvil_time+1.0f) break;
|
||||
if(m_time_since_last_shot < m_kart->getKartProperties()->getAnvilDuration() + 1.0f) break;
|
||||
|
||||
if(race_manager->getMinorMode()==RaceManager::MINOR_MODE_FOLLOW_LEADER)
|
||||
{
|
||||
@ -1378,7 +1376,7 @@ void SkiddingAI::handleItems(const float dt)
|
||||
case PowerupManager::POWERUP_SWATTER:
|
||||
{
|
||||
// Squared distance for which the swatter works
|
||||
float d2 = m_kart->getKartProperties()->getSwatterDistance2();
|
||||
float d2 = m_kart->getKartProperties()->getSwatterDistance();
|
||||
// if the kart has a shield, do not break it by using a swatter.
|
||||
if(m_kart->getShieldTime() > min_bubble_time)
|
||||
break;
|
||||
@ -2194,7 +2192,7 @@ void SkiddingAI::handleCurve()
|
||||
/** Determines if the kart should skid. The base implementation enables
|
||||
* skidding
|
||||
* \param steer_fraction The steering fraction as computed by the
|
||||
* AIBaseController.
|
||||
* AIBaseLapController.
|
||||
* \return True if the kart should skid.
|
||||
*/
|
||||
bool SkiddingAI::doSkid(float steer_fraction)
|
||||
@ -2260,7 +2258,6 @@ bool SkiddingAI::doSkid(float steer_fraction)
|
||||
// the actual path is adjusted during the turn. So apply an
|
||||
// experimentally found factor in to get better estimates.
|
||||
duration *= 1.5f;
|
||||
const Skidding *skidding = m_kart->getSkidding();
|
||||
|
||||
// If the remaining estimated time for skidding is too short, stop
|
||||
// it. This code will mostly trigger the bonus at the end of a skid.
|
||||
@ -2289,8 +2286,8 @@ bool SkiddingAI::doSkid(float steer_fraction)
|
||||
return false;
|
||||
}
|
||||
// If there is a skidding bonus, try to get it.
|
||||
else if(skidding->getNumberOfBonusTimes()>0 &&
|
||||
skidding->getTimeTillBonus(0) < duration)
|
||||
else if (m_kart->getKartProperties()->getSkidBonusSpeed().size() > 0 &&
|
||||
m_kart->getKartProperties()->getSkidTimeTillBonus()[0] < duration)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if(!m_controls->m_skid && m_ai_debug)
|
||||
|
@ -43,7 +43,7 @@
|
||||
#endif
|
||||
|
||||
|
||||
#include "karts/controller/ai_base_controller.hpp"
|
||||
#include "karts/controller/ai_base_lap_controller.hpp"
|
||||
#include "race/race_manager.hpp"
|
||||
#include "tracks/graph_node.hpp"
|
||||
#include "utils/random_generator.hpp"
|
||||
@ -111,7 +111,7 @@ the AI does the following steps:
|
||||
|
||||
\ingroup controller
|
||||
*/
|
||||
class SkiddingAI : public AIBaseController
|
||||
class SkiddingAI : public AIBaseLapController
|
||||
{
|
||||
private:
|
||||
|
||||
|
@ -78,8 +78,7 @@ ExplosionAnimation::ExplosionAnimation(AbstractKart *kart,
|
||||
m_xyz = m_kart->getXYZ();
|
||||
m_orig_y = m_xyz.getY();
|
||||
m_kart->playCustomSFX(SFXManager::CUSTOM_EXPLODE);
|
||||
m_timer = m_kart->getKartProperties()->getExplosionTime() *
|
||||
m_kart->getPlayerDifficulty()->getExplosionTime();
|
||||
m_timer = m_kart->getKartProperties()->getExplosionDuration();
|
||||
|
||||
// Non-direct hits will be only affected half as much.
|
||||
if(!direct_hit) m_timer*=0.5f;
|
||||
@ -106,8 +105,7 @@ ExplosionAnimation::ExplosionAnimation(AbstractKart *kart,
|
||||
m_add_rotation.setRoll( (rand()%(2*max_rotation+1)-max_rotation)*f );
|
||||
|
||||
// Set invulnerable time, and graphical effects
|
||||
float t = m_kart->getKartProperties()->getExplosionInvulnerabilityTime() *
|
||||
m_kart->getPlayerDifficulty()->getExplosionInvulnerabilityTime();
|
||||
float t = m_kart->getKartProperties()->getExplosionInvulnerabilityTime();
|
||||
m_kart->setInvulnerableTime(t);
|
||||
m_kart->showStarEffect(t);
|
||||
|
||||
|
@ -24,8 +24,7 @@
|
||||
|
||||
GhostKart::GhostKart(const std::string& ident)
|
||||
: Kart(ident, /*world kart id*/99999,
|
||||
/*position*/-1, btTransform(), stk_config->getPlayerDifficulty(
|
||||
PLAYER_DIFFICULTY_NORMAL))
|
||||
/*position*/-1, btTransform(), PLAYER_DIFFICULTY_NORMAL)
|
||||
{
|
||||
m_current_transform = 0;
|
||||
m_next_event = 0;
|
||||
|
@ -38,6 +38,8 @@
|
||||
#include "graphics/stk_text_billboard.hpp"
|
||||
#include "graphics/stars.hpp"
|
||||
#include "guiengine/scalable_font.hpp"
|
||||
#include "karts/abstract_characteristic.hpp"
|
||||
#include "karts/cached_characteristic.hpp"
|
||||
#include "karts/explosion_animation.hpp"
|
||||
#include "karts/kart_gfx.hpp"
|
||||
#include "karts/rescue_animation.hpp"
|
||||
@ -95,7 +97,7 @@
|
||||
*/
|
||||
Kart::Kart (const std::string& ident, unsigned int world_kart_id,
|
||||
int position, const btTransform& init_transform,
|
||||
const PlayerDifficulty *difficulty)
|
||||
PerPlayerDifficulty difficulty)
|
||||
: AbstractKart(ident, world_kart_id, position, init_transform,
|
||||
difficulty)
|
||||
|
||||
@ -111,6 +113,7 @@ Kart::Kart (const std::string& ident, unsigned int world_kart_id,
|
||||
m_race_position = position;
|
||||
m_collected_energy = 0;
|
||||
m_finished_race = false;
|
||||
m_race_result = false;
|
||||
m_finish_time = 0.0f;
|
||||
m_bubblegum_time = 0.0f;
|
||||
m_bubblegum_torque = 0.0f;
|
||||
@ -223,8 +226,7 @@ void Kart::init(RaceManager::KartType type)
|
||||
loadData(type, animations);
|
||||
|
||||
m_kart_gfx = new KartGFX(this);
|
||||
m_skidding = new Skidding(this,
|
||||
m_kart_properties->getSkiddingProperties());
|
||||
m_skidding = new Skidding(this);
|
||||
// Create the stars effect
|
||||
m_stars_effect =
|
||||
new Stars(getNode(),
|
||||
@ -363,8 +365,8 @@ void Kart::reset()
|
||||
// In case that the kart was in the air, in which case its
|
||||
// linear damping is 0
|
||||
if(m_body)
|
||||
m_body->setDamping(m_kart_properties->getChassisLinearDamping(),
|
||||
m_kart_properties->getChassisAngularDamping() );
|
||||
m_body->setDamping(m_kart_properties->getStabilityChassisLinearDamping(),
|
||||
m_kart_properties->getStabilityChassisAngularDamping());
|
||||
|
||||
if(m_terrain_sound)
|
||||
{
|
||||
@ -521,8 +523,7 @@ void Kart::blockViewWithPlunger()
|
||||
{
|
||||
// Avoid that a plunger extends the plunger time
|
||||
if(m_view_blocked_by_plunger<=0 && !isShielded())
|
||||
m_view_blocked_by_plunger =
|
||||
m_kart_properties->getPlungerInFaceTime() * m_difficulty->getPlungerInFaceTime();
|
||||
m_view_blocked_by_plunger = m_kart_properties->getPlungerInFaceTime();
|
||||
if(isShielded())
|
||||
{
|
||||
decreaseShieldTime();
|
||||
@ -553,6 +554,12 @@ btTransform Kart::getAlignedTransform(const float custom_pitch)
|
||||
return trans;
|
||||
} // getAlignedTransform
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
float Kart::getTimeFullSteer(float steer) const
|
||||
{
|
||||
return m_kart_properties->getTurnTimeFullSteer().get(steer);
|
||||
} // getTimeFullSteer
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Creates the physical representation of this kart. Atm it uses the actual
|
||||
* extention of the kart model to determine the size of the collision body.
|
||||
@ -595,7 +602,7 @@ void Kart::createPhysics()
|
||||
if (y == -1)
|
||||
{
|
||||
int index = (x + 1) / 2 + 1 - z; // get index of wheel
|
||||
float f = getKartProperties()->getPhysicalWheelPosition();
|
||||
float f = m_kart_properties->getPhysicalWheelPosition();
|
||||
// f < 0 indicates to use the old physics position, i.e.
|
||||
// to place the wheels outside of the chassis
|
||||
if(f<0)
|
||||
@ -642,8 +649,8 @@ void Kart::createPhysics()
|
||||
createBody(mass, trans, &m_kart_chassis,
|
||||
m_kart_properties->getRestitution());
|
||||
m_user_pointer.set(this);
|
||||
m_body->setDamping(m_kart_properties->getChassisLinearDamping(),
|
||||
m_kart_properties->getChassisAngularDamping() );
|
||||
m_body->setDamping(m_kart_properties->getStabilityChassisLinearDamping(),
|
||||
m_kart_properties->getStabilityChassisAngularDamping() );
|
||||
|
||||
// Reset velocities
|
||||
// ----------------
|
||||
@ -672,9 +679,9 @@ void Kart::createPhysics()
|
||||
tuning.m_maxSuspensionTravel =
|
||||
m_kart_properties->getSuspensionTravel();
|
||||
tuning.m_maxSuspensionForce =
|
||||
m_kart_properties->getMaxSuspensionForce();
|
||||
m_kart_properties->getSuspensionMaxForce();
|
||||
|
||||
const Vec3 &cs = getKartProperties()->getGravityCenterShift();
|
||||
const Vec3 &cs = m_kart_properties->getGravityCenterShift();
|
||||
for(unsigned int i=0; i<4; i++)
|
||||
{
|
||||
bool is_front_wheel = i<2;
|
||||
@ -684,10 +691,10 @@ void Kart::createPhysics()
|
||||
m_kart_model->getWheelGraphicsRadius(i),
|
||||
tuning, is_front_wheel);
|
||||
wheel.m_suspensionStiffness = m_kart_properties->getSuspensionStiffness();
|
||||
wheel.m_wheelsDampingRelaxation = m_kart_properties->getWheelDampingRelaxation();
|
||||
wheel.m_wheelsDampingCompression = m_kart_properties->getWheelDampingCompression();
|
||||
wheel.m_wheelsDampingRelaxation = m_kart_properties->getWheelsDampingRelaxation();
|
||||
wheel.m_wheelsDampingCompression = m_kart_properties->getWheelsDampingCompression();
|
||||
wheel.m_frictionSlip = m_kart_properties->getFrictionSlip();
|
||||
wheel.m_rollInfluence = m_kart_properties->getRollInfluence();
|
||||
wheel.m_rollInfluence = m_kart_properties->getStabilityRollInfluence();
|
||||
}
|
||||
// Obviously these allocs have to be properly managed/freed
|
||||
btTransform t;
|
||||
@ -780,6 +787,34 @@ void Kart::updateWeight()
|
||||
m_body->setMassProps(mass, inertia);
|
||||
} // updateWeight
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the (maximum) speed for a given turn radius.
|
||||
* \param radius The radius for which the speed needs to be computed. */
|
||||
float Kart::getSpeedForTurnRadius(float radius) const
|
||||
{
|
||||
InterpolationArray turn_angle_at_speed = m_kart_properties->getTurnRadius();
|
||||
// Convert the turn radius into turn angle
|
||||
for(std::size_t i = 0; i < turn_angle_at_speed.size(); i++)
|
||||
turn_angle_at_speed.setY(i, sin(m_kart_properties->getWheelBase() /
|
||||
turn_angle_at_speed.getY(i)));
|
||||
|
||||
float angle = sin(m_kart_properties->getWheelBase() / radius);
|
||||
return turn_angle_at_speed.getReverse(angle);
|
||||
} // getSpeedForTurnRadius
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the maximum steering angle (depending on speed). */
|
||||
float Kart::getMaxSteerAngle(float speed) const
|
||||
{
|
||||
InterpolationArray turn_angle_at_speed = m_kart_properties->getTurnRadius();
|
||||
// Convert the turn radius into turn angle
|
||||
for(std::size_t i = 0; i < turn_angle_at_speed.size(); i++)
|
||||
turn_angle_at_speed.setY(i, sin(m_kart_properties->getWheelBase() /
|
||||
turn_angle_at_speed.getY(i)));
|
||||
|
||||
return turn_angle_at_speed.get(speed);
|
||||
} // getMaxSteerAngle
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Sets that this kart has finished the race and finishing time. It also
|
||||
* notifies the race_manager about the race completion for this kart.
|
||||
@ -802,71 +837,103 @@ void Kart::finishedRace(float time)
|
||||
m_kart_model->finishedRace();
|
||||
race_manager->kartFinishedRace(this, time);
|
||||
|
||||
if ((race_manager->getMinorMode() == RaceManager::MINOR_MODE_NORMAL_RACE ||
|
||||
race_manager->getMinorMode() == RaceManager::MINOR_MODE_TIME_TRIAL ||
|
||||
race_manager->getMinorMode() == RaceManager::MINOR_MODE_FOLLOW_LEADER)
|
||||
&& m_controller->isPlayerController())
|
||||
{
|
||||
RaceGUIBase* m = World::getWorld()->getRaceGUI();
|
||||
if (m)
|
||||
{
|
||||
if (race_manager->
|
||||
getMinorMode() == RaceManager::MINOR_MODE_FOLLOW_LEADER &&
|
||||
getPosition() == 2)
|
||||
m->addMessage(_("You won the race!"), this, 2.0f);
|
||||
else if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_NORMAL_RACE ||
|
||||
race_manager->getMinorMode() == RaceManager::MINOR_MODE_TIME_TRIAL)
|
||||
{
|
||||
m->addMessage((getPosition() == 1 ?
|
||||
_("You won the race!") : _("You finished the race!")) ,
|
||||
this, 2.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_NORMAL_RACE ||
|
||||
race_manager->getMinorMode() == RaceManager::MINOR_MODE_TIME_TRIAL ||
|
||||
race_manager->getMinorMode() == RaceManager::MINOR_MODE_FOLLOW_LEADER ||
|
||||
race_manager->getMinorMode() == RaceManager::MINOR_MODE_3_STRIKES ||
|
||||
race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER ||
|
||||
race_manager->getMinorMode() == RaceManager::MINOR_MODE_EASTER_EGG)
|
||||
{
|
||||
// Save for music handling in race result gui
|
||||
setRaceResult();
|
||||
setController(new EndController(this, m_controller->getPlayer(),
|
||||
m_controller));
|
||||
|
||||
// Skip animation if this kart is eliminated
|
||||
if (m_eliminated) return;
|
||||
|
||||
m_kart_model->setAnimation(m_race_result ?
|
||||
KartModel::AF_WIN_START : KartModel::AF_LOSE_START);
|
||||
}
|
||||
} // finishedRace
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void Kart::setRaceResult()
|
||||
{
|
||||
if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_NORMAL_RACE ||
|
||||
race_manager->getMinorMode() == RaceManager::MINOR_MODE_TIME_TRIAL)
|
||||
{
|
||||
// in modes that support it, start end animation
|
||||
setController(new EndController(this, m_controller->getPlayer(),
|
||||
m_controller));
|
||||
if (m_controller->isPlayerController()) // if player is on this computer
|
||||
// TODO NetworkController?
|
||||
if (this->getController()->isPlayerController())
|
||||
{
|
||||
PlayerProfile *player = PlayerManager::getCurrentPlayer();
|
||||
const ChallengeStatus *challenge = player->getCurrentChallengeStatus();
|
||||
// In case of a GP challenge don't make the end animation depend
|
||||
// on if the challenge is fulfilled
|
||||
if(challenge && !challenge->getData()->isGrandPrix())
|
||||
if (challenge && !challenge->getData()->isGrandPrix())
|
||||
{
|
||||
if(challenge->getData()->isChallengeFulfilled())
|
||||
m_kart_model->setAnimation(KartModel::AF_WIN_START);
|
||||
if (challenge->getData()->isChallengeFulfilled())
|
||||
m_race_result = true;
|
||||
else
|
||||
m_kart_model->setAnimation(KartModel::AF_LOSE_START);
|
||||
|
||||
m_race_result = false;
|
||||
}
|
||||
else if(m_race_position<=0.5f*race_manager->getNumberOfKarts() ||
|
||||
m_race_position==1)
|
||||
m_kart_model->setAnimation(KartModel::AF_WIN_START);
|
||||
else if (this->getPosition() <= 0.5f*race_manager->getNumberOfKarts() ||
|
||||
this->getPosition() == 1)
|
||||
m_race_result = true;
|
||||
else
|
||||
m_kart_model->setAnimation(KartModel::AF_LOSE_START);
|
||||
|
||||
RaceGUIBase* m = World::getWorld()->getRaceGUI();
|
||||
if(m)
|
||||
{
|
||||
m->addMessage((getPosition() == 1 ? _("You won the race!") : _("You finished the race!")) ,
|
||||
this, 2.0f);
|
||||
}
|
||||
m_race_result = false;
|
||||
}
|
||||
}
|
||||
else if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_FOLLOW_LEADER)
|
||||
{
|
||||
// start end animation
|
||||
setController(new EndController(this, m_controller->getPlayer(),
|
||||
m_controller));
|
||||
if(m_race_position<=2)
|
||||
m_kart_model->setAnimation(KartModel::AF_WIN_START);
|
||||
else if(m_race_position>=0.7f*race_manager->getNumberOfKarts())
|
||||
m_kart_model->setAnimation(KartModel::AF_LOSE_START);
|
||||
|
||||
RaceGUIBase* m = World::getWorld()->getRaceGUI();
|
||||
if(m)
|
||||
else
|
||||
{
|
||||
if (getPosition() == 2)
|
||||
m->addMessage(_("You won the race!"), this, 2.0f);
|
||||
if (this->getPosition() <= 0.5f*race_manager->getNumberOfKarts() ||
|
||||
this->getPosition() == 1)
|
||||
m_race_result = true;
|
||||
else
|
||||
m_race_result = false;
|
||||
}
|
||||
}
|
||||
else if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_3_STRIKES ||
|
||||
race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER)
|
||||
else if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_FOLLOW_LEADER ||
|
||||
race_manager->getMinorMode() == RaceManager::MINOR_MODE_3_STRIKES)
|
||||
{
|
||||
setController(new EndController(this, m_controller->getPlayer(),
|
||||
m_controller));
|
||||
// the kart wins if it isn't eliminated
|
||||
m_race_result = !this->isEliminated();
|
||||
}
|
||||
else if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER)
|
||||
{
|
||||
// TODO complete together with soccer ai!
|
||||
m_race_result = true;
|
||||
}
|
||||
else if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_EASTER_EGG)
|
||||
{
|
||||
m_kart_model->setAnimation(KartModel::AF_WIN_START);
|
||||
setController(new EndController(this, m_controller->getPlayer(),
|
||||
m_controller));
|
||||
// Easter egg mode only has one player, so always win
|
||||
m_race_result = true;
|
||||
}
|
||||
else
|
||||
Log::warn("Kart", "Unknown game mode given.");
|
||||
|
||||
} // finishedRace
|
||||
} // setKartResult
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Called when an item is collected. It will either adjust the collected
|
||||
@ -902,16 +969,13 @@ void Kart::collectedItem(Item *item, int add_info)
|
||||
item->getEmitter()->getIdent() == "nolok");
|
||||
|
||||
// slow down
|
||||
m_bubblegum_time = m_kart_properties->getBubblegumTime() * m_difficulty->getBubblegumTime();
|
||||
m_bubblegum_time = m_kart_properties->getBubblegumDuration();
|
||||
m_bubblegum_torque = ((rand()%2)
|
||||
? m_kart_properties->getBubblegumTorque()
|
||||
: -m_kart_properties->getBubblegumTorque()) *
|
||||
m_difficulty->getBubblegumTorque();
|
||||
: -m_kart_properties->getBubblegumTorque());
|
||||
m_max_speed->setSlowdown(MaxSpeed::MS_DECREASE_BUBBLE,
|
||||
m_kart_properties->getBubblegumSpeedFraction() *
|
||||
m_difficulty->getBubblegumSpeedFraction(),
|
||||
m_kart_properties->getBubblegumFadeInTime() *
|
||||
m_difficulty->getBubblegumFadeInTime(),
|
||||
m_kart_properties->getBubblegumSpeedFraction() ,
|
||||
m_kart_properties->getBubblegumFadeInTime(),
|
||||
m_bubblegum_time);
|
||||
m_goo_sound->setPosition(getXYZ());
|
||||
m_goo_sound->play();
|
||||
@ -927,6 +991,25 @@ void Kart::collectedItem(Item *item, int add_info)
|
||||
|
||||
} // collectedItem
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Called the first time a kart accelerates after 'ready-set-go'. It searches
|
||||
* through the startup times to find the appropriate slot, and returns the
|
||||
* speed-boost from the corresponding entry.
|
||||
* If the kart started too slow (i.e. slower than the longest time in the
|
||||
* startup times list), it returns 0.
|
||||
*/
|
||||
float Kart::getStartupBoost() const
|
||||
{
|
||||
float t = World::getWorld()->getTime();
|
||||
std::vector<float> startup_times = m_kart_properties->getStartupTime();
|
||||
for (unsigned int i = 0; i < startup_times.size(); i++)
|
||||
{
|
||||
if (t <= startup_times[i])
|
||||
return m_kart_properties->getStartupBoost()[i];
|
||||
}
|
||||
return 0;
|
||||
} // getStartupBoost
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Simulates gears by adjusting the force of the engine. It also takes the
|
||||
* effect of the zipper into account.
|
||||
@ -938,21 +1021,17 @@ float Kart::getActualWheelForce()
|
||||
const std::vector<float>& gear_ratio=m_kart_properties->getGearSwitchRatio();
|
||||
for(unsigned int i=0; i<gear_ratio.size(); i++)
|
||||
{
|
||||
if(m_speed <= m_kart_properties->getMaxSpeed() *
|
||||
m_difficulty->getMaxSpeed() * gear_ratio[i])
|
||||
if(m_speed <= m_kart_properties->getEngineMaxSpeed() * gear_ratio[i])
|
||||
{
|
||||
assert(!isnan(m_kart_properties->getMaxPower() *
|
||||
m_difficulty->getMaxPower()));
|
||||
assert(!isnan(m_kart_properties->getEnginePower()));
|
||||
assert(!isnan(m_kart_properties->getGearPowerIncrease()[i]));
|
||||
return m_kart_properties->getMaxPower() *
|
||||
m_difficulty->getMaxPower()
|
||||
*m_kart_properties->getGearPowerIncrease()[i]
|
||||
+add_force;
|
||||
return m_kart_properties->getEnginePower()
|
||||
* m_kart_properties->getGearPowerIncrease()[i]
|
||||
+ add_force;
|
||||
}
|
||||
}
|
||||
assert(!isnan(m_kart_properties->getMaxPower() * m_difficulty->getMaxPower()));
|
||||
return m_kart_properties->getMaxPower() * m_difficulty->getMaxPower()
|
||||
+add_force * 2;
|
||||
assert(!isnan(m_kart_properties->getEnginePower()));
|
||||
return m_kart_properties->getEnginePower() + add_force * 2;
|
||||
|
||||
} // getActualWheelForce
|
||||
|
||||
@ -1149,12 +1228,12 @@ void Kart::update(float dt)
|
||||
// When the kart is jumping, linear damping reduces the falling speed
|
||||
// of a kart so much that it can appear to be in slow motion. So
|
||||
// disable linear damping if a kart is in the air
|
||||
m_body->setDamping(0, m_kart_properties->getChassisAngularDamping());
|
||||
m_body->setDamping(0, m_kart_properties->getStabilityChassisAngularDamping());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_body->setDamping(m_kart_properties->getChassisLinearDamping(),
|
||||
m_kart_properties->getChassisAngularDamping());
|
||||
m_body->setDamping(m_kart_properties->getStabilityChassisLinearDamping(),
|
||||
m_kart_properties->getStabilityChassisAngularDamping());
|
||||
}
|
||||
|
||||
if(m_kart_animation)
|
||||
@ -1322,7 +1401,7 @@ void Kart::update(float dt)
|
||||
static video::SColor green(255, 61, 87, 23);
|
||||
|
||||
// draw skidmarks if relevant (we force pink skidmarks on when hitting a bubblegum)
|
||||
if(m_kart_properties->getSkiddingProperties()->hasSkidmarks())
|
||||
if(m_kart_properties->getSkidEnabled())
|
||||
{
|
||||
m_skidmarks->update(dt,
|
||||
m_bubblegum_time > 0,
|
||||
@ -1365,7 +1444,7 @@ void Kart::update(float dt)
|
||||
|
||||
// Jump if either the jump is estimated to be long enough, or
|
||||
// the texture has the jump property set.
|
||||
if (t > getKartProperties()->getJumpAnimationTime() ||
|
||||
if (t > m_kart_properties->getJumpAnimationTime() ||
|
||||
last_m->isJumpTexture())
|
||||
{
|
||||
m_kart_model->setAnimation(KartModel::AF_JUMP_START);
|
||||
@ -1660,33 +1739,23 @@ void Kart::handleZipper(const Material *material, bool play_sound)
|
||||
material->getZipperParameter(&max_speed_increase, &duration,
|
||||
&speed_gain, &fade_out_time, &engine_force);
|
||||
if(max_speed_increase<0)
|
||||
max_speed_increase = m_kart_properties->getZipperMaxSpeedIncrease() *
|
||||
m_difficulty->getZipperMaxSpeedIncrease();
|
||||
max_speed_increase = m_kart_properties->getZipperMaxSpeedIncrease();
|
||||
if(duration<0)
|
||||
duration = m_kart_properties->getZipperTime() *
|
||||
m_difficulty->getZipperTime();
|
||||
duration = m_kart_properties->getZipperDuration();
|
||||
if(speed_gain<0)
|
||||
speed_gain = m_kart_properties->getZipperSpeedGain() *
|
||||
m_difficulty->getZipperSpeedGain();
|
||||
speed_gain = m_kart_properties->getZipperSpeedGain();
|
||||
if(fade_out_time<0)
|
||||
fade_out_time = m_kart_properties->getZipperFadeOutTime() *
|
||||
m_difficulty->getZipperFadeOutTime();
|
||||
fade_out_time = m_kart_properties->getZipperFadeOutTime();
|
||||
if(engine_force<0)
|
||||
engine_force = m_kart_properties->getZipperForce() *
|
||||
m_difficulty->getZipperForce();
|
||||
engine_force = m_kart_properties->getZipperForce();
|
||||
}
|
||||
else
|
||||
{
|
||||
max_speed_increase = m_kart_properties->getZipperMaxSpeedIncrease() *
|
||||
m_difficulty->getZipperMaxSpeedIncrease();
|
||||
duration = m_kart_properties->getZipperTime() *
|
||||
m_difficulty->getZipperTime();
|
||||
speed_gain = m_kart_properties->getZipperSpeedGain() *
|
||||
m_difficulty->getZipperSpeedGain();
|
||||
fade_out_time = m_kart_properties->getZipperFadeOutTime() *
|
||||
m_difficulty->getZipperFadeOutTime();
|
||||
engine_force = m_kart_properties->getZipperForce() *
|
||||
m_difficulty->getZipperForce();
|
||||
max_speed_increase = m_kart_properties->getZipperMaxSpeedIncrease();
|
||||
duration = m_kart_properties->getZipperDuration();
|
||||
speed_gain = m_kart_properties->getZipperSpeedGain();
|
||||
fade_out_time = m_kart_properties->getZipperFadeOutTime();
|
||||
engine_force = m_kart_properties->getZipperForce();
|
||||
}
|
||||
// Ignore a zipper that's activated while braking
|
||||
if(m_controls.m_brake || m_speed<0) return;
|
||||
@ -1727,8 +1796,7 @@ void Kart::updateNitro(float dt)
|
||||
return;
|
||||
}
|
||||
|
||||
m_collected_energy -= dt * m_kart_properties->getNitroConsumption() *
|
||||
m_difficulty->getNitroConsumption();
|
||||
m_collected_energy -= dt * m_kart_properties->getNitroConsumption();
|
||||
if (m_collected_energy < 0)
|
||||
{
|
||||
if(m_nitro_sound->getStatus() == SFXBase::SFX_PLAYING)
|
||||
@ -1742,14 +1810,10 @@ void Kart::updateNitro(float dt)
|
||||
if(m_nitro_sound->getStatus() != SFXBase::SFX_PLAYING)
|
||||
m_nitro_sound->play();
|
||||
m_max_speed->increaseMaxSpeed(MaxSpeed::MS_INCREASE_NITRO,
|
||||
m_kart_properties->getNitroMaxSpeedIncrease() *
|
||||
m_difficulty->getNitroMaxSpeedIncrease(),
|
||||
m_kart_properties->getNitroEngineForce() *
|
||||
m_difficulty->getNitroEngineForce(),
|
||||
m_kart_properties->getNitroDuration() *
|
||||
m_difficulty->getNitroDuration(),
|
||||
m_kart_properties->getNitroFadeOutTime() *
|
||||
m_difficulty->getNitroFadeOutTime());
|
||||
m_kart_properties->getNitroMaxSpeedIncrease(),
|
||||
m_kart_properties->getNitroEngineForce(),
|
||||
m_kart_properties->getNitroDuration(),
|
||||
m_kart_properties->getNitroFadeOutTime());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1808,7 +1872,7 @@ void Kart::crashed(const Material *m, const Vec3 &normal)
|
||||
#endif
|
||||
|
||||
const LinearWorld *lw = dynamic_cast<LinearWorld*>(World::getWorld());
|
||||
if(getKartProperties()->getTerrainImpulseType()
|
||||
if(m_kart_properties->getTerrainImpulseType()
|
||||
==KartProperties::IMPULSE_NORMAL &&
|
||||
m_vehicle->getCentralImpulseTime()<=0 )
|
||||
{
|
||||
@ -1835,7 +1899,7 @@ void Kart::crashed(const Material *m, const Vec3 &normal)
|
||||
// graph node center (we have to use the previous point since the
|
||||
// kart might have only now reached the new quad, meaning the kart
|
||||
// would be pushed forward).
|
||||
else if(getKartProperties()->getTerrainImpulseType()
|
||||
else if(m_kart_properties->getTerrainImpulseType()
|
||||
==KartProperties::IMPULSE_TO_DRIVELINE &&
|
||||
lw && m_vehicle->getCentralImpulseTime()<=0 &&
|
||||
World::getWorld()->getTrack()->isPushBackEnabled())
|
||||
@ -2038,8 +2102,7 @@ void Kart::updatePhysics(float dt)
|
||||
if(!m_has_started && m_controls.m_accel)
|
||||
{
|
||||
m_has_started = true;
|
||||
float f = m_kart_properties->getStartupBoost() *
|
||||
m_difficulty->getStartupBoost();
|
||||
float f = getStartupBoost();
|
||||
m_max_speed->instantSpeedIncrease(MaxSpeed::MS_INCREASE_ZIPPER,
|
||||
0.9f*f, f,
|
||||
/*engine_force*/200.0f,
|
||||
@ -2107,11 +2170,11 @@ void Kart::updatePhysics(float dt)
|
||||
// Only apply if near ground instead of purely based on speed avoiding
|
||||
// the "parachute on top" look.
|
||||
const Vec3 &v = m_body->getLinearVelocity();
|
||||
if(/*isNearGround() &&*/ v.getY() < - m_kart_properties->getSuspensionTravel()*60)
|
||||
if(/*isNearGround() &&*/ v.getY() < - m_kart_properties->getSuspensionTravel() * 60)
|
||||
{
|
||||
Vec3 v_clamped = v;
|
||||
// clamp the speed to 99% of the maxium falling speed.
|
||||
v_clamped.setY(-m_kart_properties->getSuspensionTravel()*60 * 0.99f);
|
||||
v_clamped.setY(-m_kart_properties->getSuspensionTravel() * 60 * 0.99f);
|
||||
//m_body->setLinearVelocity(v_clamped);
|
||||
}
|
||||
|
||||
@ -2213,8 +2276,8 @@ void Kart::updateEnginePowerAndBrakes(float dt)
|
||||
engine_power *= 5.0f;
|
||||
|
||||
// Lose some traction when skidding, to balance the advantage
|
||||
if(m_controls.m_skid &&
|
||||
m_kart_properties->getSkiddingProperties()->getSkidVisualTime()==0)
|
||||
if (m_controls.m_skid &&
|
||||
m_kart_properties->getSkidVisualTime() == 0)
|
||||
engine_power *= 0.5f;
|
||||
|
||||
applyEngineForce(engine_power*m_controls.m_accel);
|
||||
@ -2237,10 +2300,8 @@ void Kart::updateEnginePowerAndBrakes(float dt)
|
||||
m_brake_time += dt;
|
||||
// Apply the brakes - include the time dependent brake increase
|
||||
float f = 1 + m_brake_time
|
||||
* m_kart_properties->getBrakeTimeIncrease() *
|
||||
m_difficulty->getBrakeTimeIncrease();
|
||||
m_vehicle->setAllBrakes(m_kart_properties->getBrakeFactor() *
|
||||
m_difficulty->getBrakeFactor() * f);
|
||||
* m_kart_properties->getEngineBrakeTimeIncrease();
|
||||
m_vehicle->setAllBrakes(m_kart_properties->getEngineBrakeFactor() * f);
|
||||
}
|
||||
else // m_speed < 0
|
||||
{
|
||||
@ -2248,8 +2309,7 @@ void Kart::updateEnginePowerAndBrakes(float dt)
|
||||
// going backward, apply reverse gear ratio (unless he goes
|
||||
// too fast backwards)
|
||||
if ( -m_speed < m_max_speed->getCurrentMaxSpeed()
|
||||
*m_kart_properties->getMaxSpeedReverseRatio() *
|
||||
m_difficulty->getMaxSpeedReverseRatio())
|
||||
*m_kart_properties->getEngineMaxSpeedReverseRatio())
|
||||
{
|
||||
// The backwards acceleration is artificially increased to
|
||||
// allow players to get "unstuck" quicker if they hit e.g.
|
||||
@ -2418,7 +2478,7 @@ void Kart::loadData(RaceManager::KartType type, bool is_animated_model)
|
||||
|
||||
m_slipstream = new SlipStream(this);
|
||||
|
||||
if(m_kart_properties->getSkiddingProperties()->hasSkidmarks())
|
||||
if (m_kart_properties->getSkidEnabled())
|
||||
{
|
||||
m_skidmarks = new SkidMarks(*this);
|
||||
m_skidmarks->adjustFog(
|
||||
@ -2428,7 +2488,7 @@ void Kart::loadData(RaceManager::KartType type, bool is_animated_model)
|
||||
|
||||
if (!CVS->supportsShadows())
|
||||
{
|
||||
m_shadow = new Shadow(m_kart_properties, m_node,
|
||||
m_shadow = new Shadow(m_kart_properties.get(), m_node,
|
||||
-m_kart_model->getLowestPoint());
|
||||
}
|
||||
World::getWorld()->kartAdded(this, m_node);
|
||||
@ -2602,8 +2662,7 @@ void Kart::updateGraphics(float dt, const Vec3& offset_xyz,
|
||||
{
|
||||
// fabs(speed) is important, otherwise the negative number will
|
||||
// become a huge unsigned number in the particle scene node!
|
||||
nitro_frac = fabsf(getSpeed())/(m_kart_properties->getMaxSpeed() *
|
||||
m_difficulty->getMaxSpeed() );
|
||||
nitro_frac = fabsf(getSpeed()) / (m_kart_properties->getEngineMaxSpeed());
|
||||
// The speed of the kart can be higher (due to powerups) than
|
||||
// the normal maximum speed of the kart.
|
||||
if(nitro_frac>1.0f) nitro_frac = 1.0f;
|
||||
@ -2617,8 +2676,7 @@ void Kart::updateGraphics(float dt, const Vec3& offset_xyz,
|
||||
// leaning might get less if a kart gets a special that increases
|
||||
// its maximum speed, but not the current speed (by much). On the
|
||||
// other hand, that ratio can often be greater than 1.
|
||||
float speed_frac = m_speed / m_kart_properties->getMaxSpeed() *
|
||||
m_difficulty->getMaxSpeed();
|
||||
float speed_frac = m_speed / m_kart_properties->getEngineMaxSpeed();
|
||||
if(speed_frac>1.0f)
|
||||
speed_frac = 1.0f;
|
||||
else if (speed_frac < 0.0f) // no leaning when backwards driving
|
||||
@ -2626,14 +2684,14 @@ void Kart::updateGraphics(float dt, const Vec3& offset_xyz,
|
||||
|
||||
const float steer_frac = m_skidding->getSteeringFraction();
|
||||
|
||||
const float roll_speed = m_kart_properties->getLeanSpeed();
|
||||
const float roll_speed = m_kart_properties->getLeanSpeed() * DEGREE_TO_RAD;
|
||||
if(speed_frac > 0.8f && fabsf(steer_frac)>0.5f)
|
||||
{
|
||||
// Use steering ^ 7, which means less effect at lower
|
||||
// steering
|
||||
const float f = m_skidding->getSteeringFraction();
|
||||
const float f2 = f*f;
|
||||
const float max_lean = -m_kart_properties->getMaxLean()
|
||||
const float max_lean = -m_kart_properties->getLeanMax() * DEGREE_TO_RAD
|
||||
* f2*f2*f2*f
|
||||
* speed_frac;
|
||||
if(max_lean>0)
|
||||
|
@ -31,7 +31,6 @@
|
||||
#include "items/powerup.hpp"
|
||||
#include "karts/abstract_kart.hpp"
|
||||
#include "karts/kart_properties.hpp"
|
||||
#include "karts/player_difficulty.hpp"
|
||||
#include "utils/no_copy.hpp"
|
||||
|
||||
class btKart;
|
||||
@ -110,6 +109,9 @@ private:
|
||||
/** Offset of the graphical kart chassis from the physical chassis. */
|
||||
float m_graphical_y_offset;
|
||||
|
||||
/** True if the kart wins, false otherwise. */
|
||||
bool m_race_result;
|
||||
|
||||
/** True if the kart is eliminated. */
|
||||
bool m_eliminated;
|
||||
|
||||
@ -228,7 +230,7 @@ private:
|
||||
public:
|
||||
Kart(const std::string& ident, unsigned int world_kart_id,
|
||||
int position, const btTransform& init_transform,
|
||||
const PlayerDifficulty *difficulty);
|
||||
PerPlayerDifficulty difficulty);
|
||||
virtual ~Kart();
|
||||
virtual void init(RaceManager::KartType type);
|
||||
virtual void kartIsInRestNow();
|
||||
@ -236,6 +238,8 @@ public:
|
||||
const btQuaternion& off_rotation);
|
||||
virtual void createPhysics ();
|
||||
virtual void updateWeight ();
|
||||
virtual float getSpeedForTurnRadius(float radius) const;
|
||||
virtual float getMaxSteerAngle(float speed) const;
|
||||
virtual bool isInRest () const;
|
||||
virtual void applyEngineForce (float force);
|
||||
|
||||
@ -251,6 +255,8 @@ public:
|
||||
float fade_in_time);
|
||||
virtual float getSpeedIncreaseTimeLeft(unsigned int category) const;
|
||||
virtual void collectedItem(Item *item, int random_attachment);
|
||||
virtual float getStartupBoost() const;
|
||||
|
||||
virtual const Material *getMaterial() const;
|
||||
virtual const Material *getLastMaterial() const;
|
||||
/** Returns the pitch of the terrain depending on the heading. */
|
||||
@ -331,15 +337,12 @@ public:
|
||||
/** Returns the time till full steering is reached for this kart.
|
||||
* \param steer Current steer value (must be >=0), on which the time till
|
||||
* full steer depends. */
|
||||
virtual float getTimeFullSteer(float steer) const
|
||||
{
|
||||
return m_kart_properties->getTimeFullSteer(steer);
|
||||
} // getTimeFullSteer
|
||||
virtual float getTimeFullSteer(float steer) const;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the maximum steering angle for this kart, which depends on the
|
||||
* speed. */
|
||||
virtual float getMaxSteerAngle () const
|
||||
{ return m_kart_properties->getMaxSteerAngle(getSpeed()); }
|
||||
{ return getMaxSteerAngle(getSpeed()); }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the skidding object for this kart (which can be used to query
|
||||
* skidding related values). */
|
||||
@ -438,6 +441,12 @@ public:
|
||||
float getWrongwayCounter() { return m_wrongway_counter; }
|
||||
// ------------------------------------------------------------------------
|
||||
void setWrongwayCounter(float counter) { m_wrongway_counter = counter; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns whether this kart wins or loses. */
|
||||
virtual bool getRaceResult() const { return m_race_result; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Set this kart race result. */
|
||||
void setRaceResult();
|
||||
|
||||
}; // Kart
|
||||
|
||||
|
@ -326,8 +326,7 @@ void KartGFX::updateTerrain(const ParticleKind *pk)
|
||||
if (skidding > 1.0f && on_ground)
|
||||
rate = fabsf(m_kart->getControls().m_steer) > 0.8 ? skidding - 1 : 0;
|
||||
else if (speed >= 0.5f && on_ground)
|
||||
rate = speed/m_kart->getKartProperties()->getMaxSpeed() *
|
||||
m_kart->getPlayerDifficulty()->getMaxSpeed();
|
||||
rate = speed/m_kart->getKartProperties()->getEngineMaxSpeed();
|
||||
else
|
||||
{
|
||||
pe->setCreationRateAbsolute(0);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -19,6 +19,7 @@
|
||||
#ifndef HEADER_KART_PROPERTIES_HPP
|
||||
#define HEADER_KART_PROPERTIES_HPP
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@ -37,9 +38,11 @@ using namespace irr;
|
||||
#include "utils/interpolation_array.hpp"
|
||||
#include "utils/vec3.hpp"
|
||||
|
||||
class AbstractCharacteristic;
|
||||
class AIProperties;
|
||||
class CachedCharacteristic;
|
||||
class CombinedCharacteristic;
|
||||
class Material;
|
||||
class SkiddingProperties;
|
||||
class XMLNode;
|
||||
|
||||
/**
|
||||
@ -47,7 +50,7 @@ class XMLNode;
|
||||
* This includes size, name, identifier, physical properties etc.
|
||||
* It is atm also the base class for STKConfig, which stores the default values
|
||||
* for all physics constants.
|
||||
* Note that KartProperies is copied (when setting the default values from
|
||||
* Note that KartProperties is copied (when setting the default values from
|
||||
* stk_config.
|
||||
*
|
||||
* \ingroup karts
|
||||
@ -58,16 +61,11 @@ private:
|
||||
/** Base directory for this kart. */
|
||||
std::string m_root;
|
||||
|
||||
/** The skididing properties for this kart, as a separate object in order
|
||||
* to reduce dependencies (and therefore compile time) when changing
|
||||
* any skidding property. */
|
||||
SkiddingProperties *m_skidding_properties;
|
||||
|
||||
/** AI Properties for this kart, as a separate object in order to
|
||||
* reduce dependencies (and therefore compile time) when changing
|
||||
* any AI property. There is one separate object for each
|
||||
* difficulty. */
|
||||
AIProperties *m_ai_properties[RaceManager::DIFFICULTY_COUNT];
|
||||
std::shared_ptr<AIProperties> m_ai_properties[RaceManager::DIFFICULTY_COUNT];
|
||||
|
||||
/** The absolute path of the icon texture to use. */
|
||||
Material *m_icon_material;
|
||||
@ -82,7 +80,7 @@ private:
|
||||
/** The kart model and wheels. It is mutable since the wheels of the
|
||||
* KartModel can rotate and turn, and animations are played, but otherwise
|
||||
* the kart_properties object is const. */
|
||||
mutable KartModel *m_kart_model;
|
||||
mutable std::shared_ptr<KartModel> m_kart_model;
|
||||
|
||||
/** List of all groups the kart belongs to. */
|
||||
std::vector<std::string> m_groups;
|
||||
@ -119,33 +117,18 @@ private:
|
||||
* status bar and on the track-view. */
|
||||
int m_shape; /**< Number of vertices in polygon when
|
||||
* drawing the dot on the mini map. */
|
||||
|
||||
/** The physical, item, etc. characteristics of this kart that are loaded
|
||||
* from the xml file.
|
||||
*/
|
||||
std::shared_ptr<AbstractCharacteristic> m_characteristic;
|
||||
/** The base characteristics combined with the characteristics of this kart. */
|
||||
std::shared_ptr<CombinedCharacteristic> m_combined_characteristic;
|
||||
/** The cached combined characteristics. */
|
||||
std::shared_ptr<CachedCharacteristic> m_cached_characteristic;
|
||||
|
||||
// Physic properties
|
||||
// -----------------
|
||||
/** Weight of kart. */
|
||||
float m_mass;
|
||||
|
||||
/** Maximum force from engine for each difficulty. */
|
||||
std::vector<float> m_engine_power;
|
||||
|
||||
/** Braking factor * engine_power braking force. */
|
||||
float m_brake_factor;
|
||||
|
||||
/** Brake_time * m_brake_time_increase will increase the break time
|
||||
* over time. */
|
||||
float m_brake_time_increase;
|
||||
|
||||
/** Time for player karts to reach full steer angle. */
|
||||
InterpolationArray m_time_full_steer;
|
||||
|
||||
/** Time for steering to go back to zero from full steer. */
|
||||
float m_time_reset_steer;
|
||||
|
||||
/** A torque impulse applied to keep the kart parallel to the ground. */
|
||||
float m_smooth_flying_impulse;;
|
||||
|
||||
/** The turn angle depending on speed. */
|
||||
InterpolationArray m_turn_angle_at_speed;
|
||||
|
||||
/** If != 0 a bevelled box shape is used by using a point cloud as a
|
||||
* collision shape. */
|
||||
Vec3 m_bevel_factor;
|
||||
@ -159,39 +142,6 @@ private:
|
||||
*/
|
||||
float m_physical_wheel_position;
|
||||
|
||||
/** Time a kart is moved upwards after when it is rescued. */
|
||||
float m_rescue_time;
|
||||
|
||||
/** Distance the kart is raised before dropped. */
|
||||
float m_rescue_height;
|
||||
|
||||
/** Time an animated explosion is shown. Longer = more delay for kart. */
|
||||
float m_explosion_time;
|
||||
|
||||
/** How far away from an explosion karts will still be affected. */
|
||||
float m_explosion_radius;
|
||||
|
||||
/** How long a kart is invulnerable after it is hit by an explosion. */
|
||||
float m_explosion_invulnerability_time;
|
||||
|
||||
/** Duration a zipper is active. */
|
||||
float m_zipper_time;
|
||||
|
||||
/** Fade out time for a zipper. */
|
||||
float m_zipper_fade_out_time;
|
||||
|
||||
/** Additional force added to the acceleration. */
|
||||
float m_zipper_force;
|
||||
|
||||
/** Initial one time speed gain. */
|
||||
float m_zipper_speed_gain;
|
||||
|
||||
/** Absolute increase of the kart's maximum speed (in m/s). */
|
||||
float m_zipper_max_speed_increase;
|
||||
|
||||
/** Vertical offset after rescue. */
|
||||
float m_rescue_vert_offset;
|
||||
|
||||
/** Minimum time during which nitro is consumed when pressing
|
||||
* the nitro key (to prevent using in very small bursts)
|
||||
*/
|
||||
@ -202,64 +152,12 @@ private:
|
||||
|
||||
/** Filename of the wheel models. */
|
||||
std::string m_wheel_filename[4];
|
||||
/** Radius of the graphical wheels. */
|
||||
float m_wheel_graphics_radius[4];
|
||||
/** An additional Y offset added to the y position of the graphical
|
||||
* chassis. Useful for karts that don't have enough space for suspension
|
||||
* compression. */
|
||||
float m_graphical_y_offset;
|
||||
/** Max. length of plunger rubber band. */
|
||||
float m_rubber_band_max_length;
|
||||
/** Force of an attached rubber band. */
|
||||
/** Duration a rubber band works. */
|
||||
float m_rubber_band_force;
|
||||
/** How long the rubber band will fly. */
|
||||
float m_rubber_band_duration;
|
||||
/** Increase of maximum speed of the kart when the rubber band pulls. */
|
||||
float m_rubber_band_speed_increase;
|
||||
/** Fade out time when the rubber band is removed. */
|
||||
float m_rubber_band_fade_out_time;
|
||||
/**Duration of plunger in face depending on difficulty. */
|
||||
std::vector<float> m_plunger_in_face_duration;
|
||||
/** Wheel base of the kart. */
|
||||
float m_wheel_base;
|
||||
/** Nitro consumption. */
|
||||
float m_nitro_consumption;
|
||||
/** Nitro amount for small bottle. */
|
||||
float m_nitro_small_container;
|
||||
/** Nitro amount for big bittle. */
|
||||
float m_nitro_big_container;
|
||||
/** How much the speed of a kart might exceed its maximum speed (in m/s). */
|
||||
float m_nitro_max_speed_increase;
|
||||
/** Additional engine force to affect the kart. */
|
||||
float m_nitro_engine_force;
|
||||
/** How long the increased nitro max speed will be valid after
|
||||
* the kart stops using nitro (and the fade-out-time starts). */
|
||||
float m_nitro_duration;
|
||||
/** Duration during which the increased maximum speed
|
||||
* due to nitro fades out. */
|
||||
float m_nitro_fade_out_time;
|
||||
/** Maximum nitro a kart can collect. */
|
||||
float m_nitro_max;
|
||||
/** Bubble gum diration. */
|
||||
float m_bubblegum_time;
|
||||
/** Torque to add when a bubble gum was hit in order to make the kart go
|
||||
* sideways a bit. */
|
||||
float m_bubblegum_torque;
|
||||
/** Fraction of top speed that can be reached maximum after hitting a
|
||||
* bubble gum. */
|
||||
float m_bubblegum_speed_fraction;
|
||||
/** How long to fade in the slowdown for a bubble gum. */
|
||||
float m_bubblegum_fade_in_time;
|
||||
/** Square of the maximum distance a swatter can operate. */
|
||||
float m_swatter_distance2;
|
||||
/** How long the swatter lasts. */
|
||||
float m_swatter_duration;
|
||||
/** How long a kart will remain squashed. */
|
||||
float m_squash_duration;
|
||||
/** The slowdown to apply while a kart is squashed. The new maxspeed
|
||||
* is max_speed*m_squash_slowdown. */
|
||||
float m_squash_slowdown;
|
||||
|
||||
/** The maximum roll a kart graphics should show when driving in a fast
|
||||
* curve. This is read in as degrees, but stored in radians. */
|
||||
@ -269,57 +167,19 @@ private:
|
||||
* (in radians/second). */
|
||||
float m_lean_speed;
|
||||
|
||||
/** How long a jump must be in order to trigger the jump animation. */
|
||||
float m_jump_animation_time;
|
||||
|
||||
/** Engine sound effect. */
|
||||
std::string m_engine_sfx_type;
|
||||
|
||||
// bullet physics data
|
||||
// -------------------
|
||||
float m_suspension_stiffness;
|
||||
float m_wheel_damping_relaxation;
|
||||
float m_wheel_damping_compression;
|
||||
float m_max_suspension_force;
|
||||
float m_friction_slip;
|
||||
float m_roll_influence;
|
||||
|
||||
/** Parameters for the speed-weighted objects */
|
||||
SpeedWeightedObject::Properties m_speed_weighted_object_properties;
|
||||
|
||||
/** An impulse pushing the kart down which is proportional to speed. So
|
||||
* the actual impulse is speed * m_downward_impulse_factor. Set it to
|
||||
* 0 to disable completely. Based on
|
||||
* http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?f=9&t=6059\
|
||||
* &p=21240&hilit=vehicle#p21240 */
|
||||
float m_downward_impulse_factor;
|
||||
|
||||
/** Artifical acceleration that pulls a kart down onto the track if one
|
||||
* axis loses contact with the track. */
|
||||
float m_track_connection_accel;
|
||||
|
||||
/** Linear damping of the chassis to prevent it from toppling over. */
|
||||
float m_chassis_linear_damping;
|
||||
|
||||
/** Angular damping to prevent it from turning too easily. */
|
||||
float m_chassis_angular_damping;
|
||||
|
||||
/** The maximum speed at each difficulty. */
|
||||
std::vector<float> m_max_speed;
|
||||
|
||||
float m_max_speed_reverse_ratio;
|
||||
|
||||
/** Shift of center of gravity. */
|
||||
Vec3 m_gravity_center_shift;
|
||||
|
||||
/** The suspension reaction is dampened to reach an exponential behaviour.
|
||||
* See http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?f=9&t=7369\
|
||||
* &p=25236&hilit=vehicle#p25236 for details. */
|
||||
bool m_exp_spring_response;
|
||||
|
||||
float m_suspension_rest;
|
||||
float m_suspension_travel;
|
||||
|
||||
public:
|
||||
/** STK can add an impulse to push karts away from the track in case
|
||||
* of a kart-track collision. This can be done in two ways: either
|
||||
@ -345,80 +205,33 @@ private:
|
||||
/** The restitution factor to be used in collsions for this kart. */
|
||||
float m_restitution;
|
||||
|
||||
/** How far behind a kart slipstreaming is effective. */
|
||||
float m_slipstream_length;
|
||||
/** How wide the slipstream area is at the end. */
|
||||
float m_slipstream_width;
|
||||
/** Time after which sstream gives a bonus. */
|
||||
float m_slipstream_collect_time;
|
||||
/** Time slip-stream bonus is effective. */
|
||||
float m_slipstream_use_time;
|
||||
/** Additional power due to sstreaming. */
|
||||
float m_slipstream_add_power;
|
||||
/** Minimum speed for slipstream to take effect. */
|
||||
float m_slipstream_min_speed;
|
||||
/** How much the speed of the kart might exceed its
|
||||
* normal maximum speed. */
|
||||
float m_slipstream_max_speed_increase;
|
||||
/** How long the higher speed lasts after slipstream stopped working. */
|
||||
float m_slipstream_duration;
|
||||
/** How long the slip stream speed increase will gradually be reduced. */
|
||||
float m_slipstream_fade_out_time;
|
||||
|
||||
/** Distance of normal camera from kart. */
|
||||
float m_camera_distance;
|
||||
|
||||
/** Up angle of the camera in relation to the pitch of the kart when
|
||||
* driving forwards. */
|
||||
float m_camera_forward_up_angle;
|
||||
|
||||
/** Up angle of the camera in relation to the pitch of the kart when
|
||||
* driving backwards. */
|
||||
float m_camera_backward_up_angle;
|
||||
|
||||
/** The following two vectors define at what ratio of the maximum speed what
|
||||
* gear is selected. E.g. 0.25 means: if speed <=0.25*maxSpeed --> gear 1,
|
||||
* 0.5 means: if speed <=0.5 *maxSpeed --> gear 2 */
|
||||
std::vector<float> m_gear_switch_ratio;
|
||||
/** This vector contains the increase in max power (to simulate different
|
||||
* gears), e.g. 2.5 as first entry means: 2.5*maxPower in gear 1. See
|
||||
m_gear_switch_ratio). */
|
||||
std::vector<float> m_gear_power_increase;
|
||||
|
||||
/** If the kart starts within the specified time at index I after 'go',
|
||||
* it receives the speed boost from m_startup_boost[I]. */
|
||||
std::vector<float> m_startup_times;
|
||||
|
||||
/** The startup boost is the kart starts fast enough. */
|
||||
std::vector<float> m_startup_boost;
|
||||
|
||||
|
||||
void load (const std::string &filename,
|
||||
const std::string &node);
|
||||
|
||||
void combineCharacteristics();
|
||||
|
||||
public:
|
||||
/** Returns the string representation of a per-player difficulty. */
|
||||
static std::string getPerPlayerDifficultyAsString(PerPlayerDifficulty d);
|
||||
|
||||
KartProperties (const std::string &filename="");
|
||||
~KartProperties ();
|
||||
void copyForPlayer (const KartProperties *source);
|
||||
void copyFrom (const KartProperties *source);
|
||||
void getAllData (const XMLNode * root);
|
||||
void checkAllSet (const std::string &filename);
|
||||
float getStartupBoost () const;
|
||||
bool isInGroup (const std::string &group) const;
|
||||
bool operator<(const KartProperties &other) const;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the (maximum) speed for a given turn radius.
|
||||
* \param radius The radius for which the speed needs to be computed. */
|
||||
float getSpeedForTurnRadius(float radius) const {
|
||||
float angle = sin(m_wheel_base / radius);
|
||||
return m_turn_angle_at_speed.getReverse(angle);
|
||||
} // getSpeedForTurnRadius
|
||||
/** Returns the characteristics for this kart. */
|
||||
const AbstractCharacteristic* getCharacteristic() const;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the maximum steering angle (depending on speed). */
|
||||
float getMaxSteerAngle(float speed) const {
|
||||
return m_turn_angle_at_speed.get(speed);
|
||||
} // getMaxSteerAngle
|
||||
/** Returns the characteristics for this kart combined with the base
|
||||
* characteristic. This value isn't used for the race, because the
|
||||
* difficulty is missing, but it can be used e.g. for the kart stats widget.
|
||||
*/
|
||||
const AbstractCharacteristic* getCombinedCharacteristic() const;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the material for the kart icons. */
|
||||
@ -462,6 +275,10 @@ public:
|
||||
/** Returns the internal identifier of this kart. */
|
||||
const std::string& getIdent () const {return m_ident; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the type of this kart. */
|
||||
const std::string& getKartType () const { return m_kart_type; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the shadow texture to use. */
|
||||
video::ITexture *getShadowTexture() const {return m_shadow_texture; }
|
||||
@ -492,47 +309,6 @@ public:
|
||||
/** Returns the list of groups this kart belongs to. */
|
||||
const std::vector<std::string>&
|
||||
getGroups () const {return m_groups; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the mass of this kart. */
|
||||
float getMass () const {return m_mass; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the maximum engine power depending on difficulty. */
|
||||
float getMaxPower () const
|
||||
{return m_engine_power[race_manager->getDifficulty()];}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the time the kart needs to fully steer in one direction from
|
||||
* steering straight depending on the current steering value.
|
||||
* \param steer Current steering value, must be >=0. */
|
||||
float getTimeFullSteer(float steer) const
|
||||
{
|
||||
assert(steer>=0);
|
||||
return m_time_full_steer.get(steer);
|
||||
} // getTimeFullSteer
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the time the kart needs to go back to steering straight from
|
||||
* full steer. */
|
||||
float getTimeResetSteer () const { return m_time_reset_steer; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Get braking information. */
|
||||
float getBrakeFactor () const {return m_brake_factor; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the additional brake factor which depends on time. */
|
||||
float getBrakeTimeIncrease() const { return m_brake_time_increase; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the torque scaling factor used to keep the karts parallel to
|
||||
* the ground when flying. */
|
||||
float getSmoothFlyingImpulse() const
|
||||
{
|
||||
return m_smooth_flying_impulse;
|
||||
} // getSmoothFlyingImpulse
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Get maximum reverse speed ratio. */
|
||||
float getMaxSpeedReverseRatio() const {return m_max_speed_reverse_ratio; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the engine type (used to change sfx depending on kart size). */
|
||||
@ -540,31 +316,9 @@ public:
|
||||
|
||||
// Bullet physics get functions
|
||||
//-----------------------------
|
||||
/** Returns the suspension stiffness. */
|
||||
float getSuspensionStiffness () const {return m_suspension_stiffness; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns damping relaxation. */
|
||||
float getWheelDampingRelaxation () const
|
||||
{return m_wheel_damping_relaxation; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the wheel damping compression. */
|
||||
float getWheelDampingCompression() const
|
||||
{return m_wheel_damping_compression;}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns maximum suspension force. */
|
||||
float getMaxSuspensionForce() const {return m_max_suspension_force; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns friction slip. */
|
||||
float getFrictionSlip () const {return m_friction_slip; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns roll influence. */
|
||||
float getRollInfluence () const {return m_roll_influence; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns parameters for the speed-weighted objects */
|
||||
const SpeedWeightedObject::Properties& getSpeedWeightedObjectProperties() const
|
||||
@ -576,99 +330,11 @@ public:
|
||||
/** Returns the wheel base (distance front to rear axis). */
|
||||
float getWheelBase () const {return m_wheel_base; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns linear damping of chassis. */
|
||||
float getChassisLinearDamping () const {return m_chassis_linear_damping;}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns angular damping of chassis. */
|
||||
float getChassisAngularDamping () const
|
||||
{return m_chassis_angular_damping; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Artifical downward impulse every frame. */
|
||||
float getDownwardImpulseFactor() const { return m_downward_impulse_factor;}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns artificial acceleration to keep wheels on track. */
|
||||
float getTrackConnectionAccel () const {return m_track_connection_accel;}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the maximum speed dependent on the difficult level. */
|
||||
float getMaxSpeed () const
|
||||
{
|
||||
return m_max_speed[race_manager->getDifficulty()];
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Return the absolute maximum speed, independent on the difficulty. */
|
||||
float getAbsMaxSpeed () const
|
||||
{
|
||||
return m_max_speed[m_max_speed.size()-1];
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the nitro consumption. */
|
||||
float getNitroConsumption () const {return m_nitro_consumption; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the amount of nitro for a small container. */
|
||||
float getNitroSmallContainer () const {return m_nitro_small_container; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the amount of nitro for a big container. */
|
||||
float getNitroBigContainer () const {return m_nitro_big_container; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the increase of maximum speed due to nitro. */
|
||||
float getNitroMaxSpeedIncrease () const
|
||||
{return m_nitro_max_speed_increase; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
float getNitroEngineForce () const {return m_nitro_engine_force; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns how long the increased nitro max speed will be valid after
|
||||
* the kart stops using nitro (and the fade-out-time starts). */
|
||||
float getNitroDuration () const {return m_nitro_duration; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the duration during which the increased maximum speed
|
||||
* due to nitro fades out. */
|
||||
float getNitroFadeOutTime () const {return m_nitro_fade_out_time; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the maximum amount of nitro a kart can store. */
|
||||
float getNitroMax () const {return m_nitro_max; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns how long a bubble gum is active. */
|
||||
float getBubblegumTime() const { return m_bubblegum_time; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the torque to add when a bubble gum was hit . */
|
||||
float getBubblegumTorque() const { return m_bubblegum_torque; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the fraction of top speed that can be reached maximum after
|
||||
* hitting a bubble gum. */
|
||||
float getBubblegumSpeedFraction() const {return m_bubblegum_speed_fraction;}
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns how long to fade in the slowdown for a bubble gum. */
|
||||
float getBubblegumFadeInTime() const { return m_bubblegum_fade_in_time; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns a shift of the center of mass (lowering the center of mass
|
||||
* makes the karts more stable. */
|
||||
const Vec3&getGravityCenterShift() const {return m_gravity_center_shift; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Retusn suspension rest length. */
|
||||
float getSuspensionRest () const {return m_suspension_rest; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the amount the suspension can extend. */
|
||||
float getSuspensionTravel () const {return m_suspension_travel; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns if the spring should be exponentially dampened. */
|
||||
bool getExpSpringResponse() const {return m_exp_spring_response; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns an artificial impulse to push karts away from the terrain
|
||||
* it hits. */
|
||||
@ -693,128 +359,6 @@ public:
|
||||
/** Returns the restitution factor for this kart. */
|
||||
float getRestitution () const { return m_restitution; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the vertical offset when rescuing karts to avoid karts being
|
||||
* rescued in (or under) the track. */
|
||||
float getVertRescueOffset () const {return m_rescue_vert_offset; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the time a kart is rised during a rescue. */
|
||||
float getRescueTime () const {return m_rescue_time; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the height a kart is moved to during a rescue. */
|
||||
float getRescueHeight () const {return m_rescue_height; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the time an explosion animation is shown. */
|
||||
float getExplosionTime () const {return m_explosion_time; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the height of the explosion animation. */
|
||||
float getExplosionRadius () const {return m_explosion_radius; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns how long a kart is invulnerable after being hit by an
|
||||
explosion. */
|
||||
float getExplosionInvulnerabilityTime() const
|
||||
{ return m_explosion_invulnerability_time; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the maximum length of a rubber band before it breaks. */
|
||||
float getRubberBandMaxLength () const {return m_rubber_band_max_length;}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns force a rubber band has when attached to a kart. */
|
||||
float getRubberBandForce () const {return m_rubber_band_force; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the duration a rubber band is active for. */
|
||||
float getRubberBandDuration () const {return m_rubber_band_duration; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the increase of maximum speed while a rubber band is
|
||||
* pulling. */
|
||||
float getRubberBandSpeedIncrease() const
|
||||
{
|
||||
return m_rubber_band_speed_increase;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Return the fade out time once a rubber band is removed. */
|
||||
float getRubberBandFadeOutTime() const
|
||||
{
|
||||
return m_rubber_band_fade_out_time;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns duration of a plunger in your face. */
|
||||
float getPlungerInFaceTime () const
|
||||
{return m_plunger_in_face_duration[race_manager->getDifficulty()];}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the time a zipper is active. */
|
||||
float getZipperTime () const {return m_zipper_time; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the time a zipper is active. */
|
||||
float getZipperFadeOutTime () const {return m_zipper_fade_out_time; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the additional force added applied to the kart. */
|
||||
float getZipperForce () const { return m_zipper_force; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the initial zipper speed gain. */
|
||||
float getZipperSpeedGain () const { return m_zipper_speed_gain; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the increase of the maximum speed of the kart
|
||||
* if a zipper is active. */
|
||||
float getZipperMaxSpeedIncrease () const
|
||||
{ return m_zipper_max_speed_increase;}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns how far behind a kart slipstreaming works. */
|
||||
float getSlipstreamLength () const {return m_slipstream_length; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns how wide the slipstream area is at the end. */
|
||||
float getSlipstreamWidth () const {return m_slipstream_width; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns time after which slipstream has maximum effect. */
|
||||
float getSlipstreamCollectTime () const
|
||||
{return m_slipstream_collect_time; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns time after which slipstream has maximum effect. */
|
||||
float getSlipstreamUseTime () const {return m_slipstream_use_time; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns additional power due to slipstreaming. */
|
||||
float getSlipstreamAddPower () const {return m_slipstream_add_power; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the minimum slipstream speed. */
|
||||
float getSlipstreamMinSpeed () const {return m_slipstream_min_speed; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the increase of the maximum speed of a kart
|
||||
* due to slipstream. */
|
||||
float getSlipstreamMaxSpeedIncrease() const
|
||||
{ return m_slipstream_max_speed_increase; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns how long the higher speed lasts after slipstream
|
||||
* stopped working. */
|
||||
float getSlipstreamDuration () const { return m_slipstream_duration; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns how long the slip stream speed increase will gradually
|
||||
* be reduced. */
|
||||
float getSlipstreamFadeOutTime () const
|
||||
{ return m_slipstream_fade_out_time; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the scale factor by which the shadow plane
|
||||
* had to be set. */
|
||||
@ -830,79 +374,18 @@ public:
|
||||
* had to be set. */
|
||||
float getShadowZOffset () const {return m_shadow_z_offset; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns a pointer to the skidding properties. */
|
||||
const SkiddingProperties *getSkiddingProperties() const
|
||||
{ return m_skidding_properties; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns a pointer to the AI properties. */
|
||||
const AIProperties *getAIPropertiesForDifficulty() const
|
||||
{
|
||||
return m_ai_properties[race_manager->getDifficulty()];
|
||||
return m_ai_properties[race_manager->getDifficulty()].get();
|
||||
} // getAIProperties
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns ratio of current speed to max speed at which the gear will
|
||||
* change (for our simualated gears = simple change of engine power). */
|
||||
const std::vector<float>&
|
||||
getGearSwitchRatio () const {return m_gear_switch_ratio; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the power increase depending on gear. */
|
||||
const std::vector<float>&
|
||||
getGearPowerIncrease () const {return m_gear_power_increase; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the average power of the kart (in all gears). */
|
||||
const float getAvgPower () const;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns distance between kart and camera. */
|
||||
float getCameraDistance () const {return m_camera_distance; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the angle the camera has relative to the pitch of the kart. */
|
||||
float getCameraForwardUpAngle () const
|
||||
{return m_camera_forward_up_angle; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the angle the camera has relative to the pitch of the kart. */
|
||||
float getCameraBackwardUpAngle () const
|
||||
{return m_camera_backward_up_angle; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the full path where the files for this kart are stored. */
|
||||
const std::string& getKartDir () const {return m_root; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the square of the maximum distance at which a swatter
|
||||
* can hit karts. */
|
||||
float getSwatterDistance2() const { return m_swatter_distance2; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns how long a swatter will stay attached/ready to be used. */
|
||||
float getSwatterDuration() const { return m_swatter_duration; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns how long a kart remains squashed. */
|
||||
float getSquashDuration() const {return m_squash_duration; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the slowdown of a kart that is squashed. */
|
||||
float getSquashSlowdown() const {return m_squash_slowdown; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** The maximum leaning a kart should show (In radians). */
|
||||
float getMaxLean() const { return m_max_lean; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** The speed with which a kart should lean (in radians/s). */
|
||||
float getLeanSpeed() const { return m_lean_speed; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Return show long a jump must last in order to play the jump
|
||||
* animation. */
|
||||
float getJumpAnimationTime() const { return m_jump_animation_time; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns minimum time during which nitro is consumed when pressing nitro
|
||||
* key, to prevent using nitro in very short bursts
|
||||
@ -921,8 +404,142 @@ public:
|
||||
{
|
||||
return m_physical_wheel_position;
|
||||
} // getPhysicalWheelPosition
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
float getAvgPower() const;
|
||||
|
||||
|
||||
// Script-generated content generated by tools/create_kart_properties.py defs
|
||||
// Please don't change the following tag. It will be automatically detected
|
||||
// by the script and replace the contained content.
|
||||
// To update the code, use tools/update_characteristics.py
|
||||
/* <characteristics-start kpdefs> */
|
||||
|
||||
float getSuspensionStiffness() const;
|
||||
float getSuspensionRest() const;
|
||||
float getSuspensionTravel() const;
|
||||
bool getSuspensionExpSpringResponse() const;
|
||||
float getSuspensionMaxForce() const;
|
||||
|
||||
float getStabilityRollInfluence() const;
|
||||
float getStabilityChassisLinearDamping() const;
|
||||
float getStabilityChassisAngularDamping() const;
|
||||
float getStabilityDownwardImpulseFactor() const;
|
||||
float getStabilityTrackConnectionAccel() const;
|
||||
float getStabilitySmoothFlyingImpulse() const;
|
||||
|
||||
InterpolationArray getTurnRadius() const;
|
||||
float getTurnTimeResetSteer() const;
|
||||
InterpolationArray getTurnTimeFullSteer() const;
|
||||
|
||||
float getEnginePower() const;
|
||||
float getEngineMaxSpeed() const;
|
||||
float getEngineBrakeFactor() const;
|
||||
float getEngineBrakeTimeIncrease() const;
|
||||
float getEngineMaxSpeedReverseRatio() const;
|
||||
|
||||
std::vector<float> getGearSwitchRatio() const;
|
||||
std::vector<float> getGearPowerIncrease() const;
|
||||
|
||||
float getMass() const;
|
||||
|
||||
float getWheelsDampingRelaxation() const;
|
||||
float getWheelsDampingCompression() const;
|
||||
|
||||
float getCameraDistance() const;
|
||||
float getCameraForwardUpAngle() const;
|
||||
float getCameraBackwardUpAngle() const;
|
||||
|
||||
float getJumpAnimationTime() const;
|
||||
|
||||
float getLeanMax() const;
|
||||
float getLeanSpeed() const;
|
||||
|
||||
float getAnvilDuration() const;
|
||||
float getAnvilWeight() const;
|
||||
float getAnvilSpeedFactor() const;
|
||||
|
||||
float getParachuteFriction() const;
|
||||
float getParachuteDuration() const;
|
||||
float getParachuteDurationOther() const;
|
||||
float getParachuteLboundFraction() const;
|
||||
float getParachuteUboundFraction() const;
|
||||
float getParachuteMaxSpeed() const;
|
||||
|
||||
float getBubblegumDuration() const;
|
||||
float getBubblegumSpeedFraction() const;
|
||||
float getBubblegumTorque() const;
|
||||
float getBubblegumFadeInTime() const;
|
||||
float getBubblegumShieldDuration() const;
|
||||
|
||||
float getZipperDuration() const;
|
||||
float getZipperForce() const;
|
||||
float getZipperSpeedGain() const;
|
||||
float getZipperMaxSpeedIncrease() const;
|
||||
float getZipperFadeOutTime() const;
|
||||
|
||||
float getSwatterDuration() const;
|
||||
float getSwatterDistance() const;
|
||||
float getSwatterSquashDuration() const;
|
||||
float getSwatterSquashSlowdown() const;
|
||||
|
||||
float getPlungerBandMaxLength() const;
|
||||
float getPlungerBandForce() const;
|
||||
float getPlungerBandDuration() const;
|
||||
float getPlungerBandSpeedIncrease() const;
|
||||
float getPlungerBandFadeOutTime() const;
|
||||
float getPlungerInFaceTime() const;
|
||||
|
||||
std::vector<float> getStartupTime() const;
|
||||
std::vector<float> getStartupBoost() const;
|
||||
|
||||
float getRescueDuration() const;
|
||||
float getRescueVertOffset() const;
|
||||
float getRescueHeight() const;
|
||||
|
||||
float getExplosionDuration() const;
|
||||
float getExplosionRadius() const;
|
||||
float getExplosionInvulnerabilityTime() const;
|
||||
|
||||
float getNitroDuration() const;
|
||||
float getNitroEngineForce() const;
|
||||
float getNitroConsumption() const;
|
||||
float getNitroSmallContainer() const;
|
||||
float getNitroBigContainer() const;
|
||||
float getNitroMaxSpeedIncrease() const;
|
||||
float getNitroFadeOutTime() const;
|
||||
float getNitroMax() const;
|
||||
|
||||
float getSlipstreamDuration() const;
|
||||
float getSlipstreamLength() const;
|
||||
float getSlipstreamWidth() const;
|
||||
float getSlipstreamCollectTime() const;
|
||||
float getSlipstreamUseTime() const;
|
||||
float getSlipstreamAddPower() const;
|
||||
float getSlipstreamMinSpeed() const;
|
||||
float getSlipstreamMaxSpeedIncrease() const;
|
||||
float getSlipstreamFadeOutTime() const;
|
||||
|
||||
float getSkidIncrease() const;
|
||||
float getSkidDecrease() const;
|
||||
float getSkidMax() const;
|
||||
float getSkidTimeTillMax() const;
|
||||
float getSkidVisual() const;
|
||||
float getSkidVisualTime() const;
|
||||
float getSkidRevertVisualTime() const;
|
||||
float getSkidMinSpeed() const;
|
||||
std::vector<float> getSkidTimeTillBonus() const;
|
||||
std::vector<float> getSkidBonusSpeed() const;
|
||||
std::vector<float> getSkidBonusTime() const;
|
||||
std::vector<float> getSkidBonusForce() const;
|
||||
float getSkidPhysicalJumpTime() const;
|
||||
float getSkidGraphicalJumpTime() const;
|
||||
float getSkidPostSkidRotateFactor() const;
|
||||
float getSkidReduceTurnMin() const;
|
||||
float getSkidReduceTurnMax() const;
|
||||
bool getSkidEnabled() const;
|
||||
|
||||
/* <characteristics-end kpdefs> */
|
||||
}; // KartProperties
|
||||
|
||||
#endif
|
||||
|
||||
/* EOF */
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "guiengine/engine.hpp"
|
||||
#include "io/file_manager.hpp"
|
||||
#include "karts/kart_properties.hpp"
|
||||
#include "karts/xml_characteristic.hpp"
|
||||
#include "utils/log.hpp"
|
||||
#include "utils/string_utils.hpp"
|
||||
|
||||
@ -175,12 +176,68 @@ void KartPropertiesManager::loadAllKarts(bool loading_icon)
|
||||
} // loadAllKarts
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Loads a single kart and (if not disabled) the oorresponding 3d model.
|
||||
/** Loads the characteristics from the characteristics config file.
|
||||
* \param root The xml node where the characteristics are stored.
|
||||
*/
|
||||
void KartPropertiesManager::loadCharacteristics(const XMLNode *root)
|
||||
{
|
||||
// Load base characteristics
|
||||
std::vector<XMLNode*> nodes;
|
||||
root->getNodes("characteristic", nodes);
|
||||
bool found = false;
|
||||
std::string name;
|
||||
for (const XMLNode *baseNode : nodes)
|
||||
{
|
||||
baseNode->get("name", &name);
|
||||
if (name == "base")
|
||||
{
|
||||
found = true;
|
||||
m_base_characteristic.reset(new XmlCharacteristic(baseNode));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
Log::fatal("KartPropertiesManager", "Base characteristics not found");
|
||||
|
||||
// Load difficulties
|
||||
nodes.clear();
|
||||
root->getNode("difficulties")->getNodes("characteristic", nodes);
|
||||
for (const XMLNode *type : nodes)
|
||||
{
|
||||
type->get("name", &name);
|
||||
m_difficulty_characteristics.insert(std::pair<const std::string,
|
||||
std::unique_ptr<AbstractCharacteristic> >(name,
|
||||
std::unique_ptr<AbstractCharacteristic>(new XmlCharacteristic(type))));
|
||||
}
|
||||
// Load kart type characteristics
|
||||
nodes.clear();
|
||||
root->getNode("kart-types")->getNodes("characteristic", nodes);
|
||||
for (const XMLNode *type : nodes)
|
||||
{
|
||||
type->get("name", &name);
|
||||
m_kart_type_characteristics.insert(std::pair<const std::string,
|
||||
std::unique_ptr<AbstractCharacteristic> >(name,
|
||||
std::unique_ptr<AbstractCharacteristic>(new XmlCharacteristic(type))));
|
||||
}
|
||||
// Load player difficulties
|
||||
nodes.clear();
|
||||
root->getNode("player-characteristics")->getNodes("characteristic", nodes);
|
||||
for (const XMLNode *type : nodes)
|
||||
{
|
||||
type->get("name", &name);
|
||||
m_player_characteristics.insert(std::pair<const std::string,
|
||||
std::unique_ptr<AbstractCharacteristic> >(name,
|
||||
std::unique_ptr<AbstractCharacteristic>(new XmlCharacteristic(type))));
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Loads a single kart and (if not disabled) the corresponding 3d model.
|
||||
* \param filename Full path to the kart config file.
|
||||
*/
|
||||
bool KartPropertiesManager::loadKart(const std::string &dir)
|
||||
{
|
||||
std::string config_filename=dir+"/kart.xml";
|
||||
std::string config_filename = dir + "/kart.xml";
|
||||
if(!file_manager->fileExists(config_filename))
|
||||
return false;
|
||||
|
||||
@ -191,7 +248,7 @@ bool KartPropertiesManager::loadKart(const std::string &dir)
|
||||
}
|
||||
catch (std::runtime_error& err)
|
||||
{
|
||||
Log::error("[Kart_Properties_Manager]","Giving up loading '%s': %s",
|
||||
Log::error("[KartPropertiesManager]", "Giving up loading '%s': %s",
|
||||
config_filename.c_str(), err.what());
|
||||
return false;
|
||||
}
|
||||
@ -201,7 +258,7 @@ bool KartPropertiesManager::loadKart(const std::string &dir)
|
||||
if (kart_properties->getVersion() < stk_config->m_min_kart_version ||
|
||||
kart_properties->getVersion() > stk_config->m_max_kart_version)
|
||||
{
|
||||
Log::warn("[Kart_Properties_Manager]", "Warning: kart '%s' is not "
|
||||
Log::warn("[KartPropertiesManager]", "Warning: kart '%s' is not "
|
||||
"supported by this binary, ignored.",
|
||||
kart_properties->getIdent().c_str());
|
||||
delete kart_properties;
|
||||
@ -221,7 +278,7 @@ bool KartPropertiesManager::loadKart(const std::string &dir)
|
||||
}
|
||||
m_all_kart_dirs.push_back(dir);
|
||||
return true;
|
||||
} // loadKartData
|
||||
} // loadKart
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Sets the name of a mesh to use as a hat for all karts.
|
||||
@ -235,6 +292,36 @@ void KartPropertiesManager::setHatMeshName(const std::string &hat_name)
|
||||
}
|
||||
} // setHatMeshName
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
const AbstractCharacteristic* KartPropertiesManager::getDifficultyCharacteristic(const std::string &type) const
|
||||
{
|
||||
std::map<std::string, std::unique_ptr<AbstractCharacteristic> >::const_iterator
|
||||
it = m_difficulty_characteristics.find(type);
|
||||
if (it == m_difficulty_characteristics.cend())
|
||||
return nullptr;
|
||||
return it->second.get();
|
||||
} // getDifficultyCharacteristic
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
const AbstractCharacteristic* KartPropertiesManager::getKartTypeCharacteristic(const std::string &type) const
|
||||
{
|
||||
std::map<std::string, std::unique_ptr<AbstractCharacteristic> >::const_iterator
|
||||
it = m_kart_type_characteristics.find(type);
|
||||
if (it == m_kart_type_characteristics.cend())
|
||||
return nullptr;
|
||||
return it->second.get();
|
||||
} // getKartTypeCharacteristic
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
const AbstractCharacteristic* KartPropertiesManager::getPlayerCharacteristic(const std::string &type) const
|
||||
{
|
||||
std::map<std::string, std::unique_ptr<AbstractCharacteristic> >::const_iterator
|
||||
it = m_player_characteristics.find(type);
|
||||
if (it == m_player_characteristics.cend())
|
||||
return nullptr;
|
||||
return it->second.get();
|
||||
} // getPlayerCharacteristic
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Returns index of the kart properties with the given ident.
|
||||
* \return Index of kart (between 0 and number of karts - 1).
|
||||
|
@ -22,13 +22,16 @@
|
||||
|
||||
#include "utils/ptr_vector.hpp"
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
#include "network/remote_kart_info.hpp"
|
||||
#include "utils/no_copy.hpp"
|
||||
|
||||
#define ALL_KART_GROUPS_ID "all"
|
||||
|
||||
class AbstractCharacteristic;
|
||||
class KartProperties;
|
||||
class XMLNode;
|
||||
|
||||
/**
|
||||
* \ingroup karts
|
||||
@ -58,6 +61,11 @@ private:
|
||||
* all clients or not. */
|
||||
std::vector<bool> m_kart_available;
|
||||
|
||||
std::unique_ptr<AbstractCharacteristic> m_base_characteristic;
|
||||
std::map<std::string, std::unique_ptr<AbstractCharacteristic> > m_difficulty_characteristics;
|
||||
std::map<std::string, std::unique_ptr<AbstractCharacteristic> > m_kart_type_characteristics;
|
||||
std::map<std::string, std::unique_ptr<AbstractCharacteristic> > m_player_characteristics;
|
||||
|
||||
protected:
|
||||
|
||||
typedef PtrVector<KartProperties> KartPropertiesVector;
|
||||
@ -74,6 +82,7 @@ public:
|
||||
int getKartByGroup(const std::string& group,
|
||||
int i) const;
|
||||
|
||||
void loadCharacteristics (const XMLNode *root);
|
||||
bool loadKart (const std::string &dir);
|
||||
void loadAllKarts (bool loading_icon = true);
|
||||
void unloadAllKarts ();
|
||||
@ -89,6 +98,18 @@ public:
|
||||
std::vector<std::string> *ai_list);
|
||||
void setHatMeshName(const std::string &hat_name);
|
||||
// ------------------------------------------------------------------------
|
||||
/** Get the characteristic that holds the base values. */
|
||||
const AbstractCharacteristic* getBaseCharacteristic() const { return m_base_characteristic.get(); }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Get a characteristic that holds the values for a certain difficulty. */
|
||||
const AbstractCharacteristic* getDifficultyCharacteristic(const std::string &type) const;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Get a characteristic that holds the values for a kart type. */
|
||||
const AbstractCharacteristic* getKartTypeCharacteristic(const std::string &type) const;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Get a characteristic that holds the values for a player difficulty. */
|
||||
const AbstractCharacteristic* getPlayerCharacteristic(const std::string &type) const;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns a list of all groups. */
|
||||
const std::vector<std::string>& getAllGroups() const {return m_all_groups;}
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -26,7 +26,7 @@
|
||||
KartWithStats::KartWithStats(const std::string& ident,
|
||||
unsigned int world_kart_id,
|
||||
int position, const btTransform& init_transform,
|
||||
const PlayerDifficulty *difficulty)
|
||||
PerPlayerDifficulty difficulty)
|
||||
: Kart(ident, world_kart_id, position,
|
||||
init_transform, difficulty)
|
||||
{
|
||||
|
@ -75,7 +75,7 @@ public:
|
||||
unsigned int world_kart_id,
|
||||
int position,
|
||||
const btTransform& init_transform,
|
||||
const PlayerDifficulty *difficulty);
|
||||
PerPlayerDifficulty difficulty);
|
||||
virtual void update(float dt);
|
||||
virtual void reset();
|
||||
virtual void collectedItem(Item *item, int add_info);
|
||||
|
@ -62,8 +62,7 @@ MaxSpeed::MaxSpeed(AbstractKart *kart)
|
||||
*/
|
||||
void MaxSpeed::reset()
|
||||
{
|
||||
m_current_max_speed = m_kart->getKartProperties()->getMaxSpeed() *
|
||||
m_kart->getPlayerDifficulty()->getMaxSpeed();
|
||||
m_current_max_speed = m_kart->getKartProperties()->getEngineMaxSpeed();
|
||||
m_min_speed = -1.0f;
|
||||
|
||||
for(unsigned int i=MS_DECREASE_MIN; i<MS_DECREASE_MAX; i++)
|
||||
@ -243,8 +242,7 @@ void MaxSpeed::update(float dt)
|
||||
}
|
||||
|
||||
m_add_engine_force = 0;
|
||||
m_current_max_speed = m_kart->getKartProperties()->getMaxSpeed() *
|
||||
m_kart->getPlayerDifficulty()->getMaxSpeed();
|
||||
m_current_max_speed = m_kart->getKartProperties()->getEngineMaxSpeed();
|
||||
|
||||
// Then add the speed increase from each category
|
||||
// ----------------------------------------------
|
||||
|
@ -1,199 +0,0 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2006-2015 SuperTuxKart-Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#include "karts/player_difficulty.hpp"
|
||||
|
||||
#include "config/stk_config.hpp"
|
||||
#include "io/xml_node.hpp"
|
||||
#include "karts/skidding_properties.hpp"
|
||||
#include "race/race_manager.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
/**
|
||||
* The constructor initialises all values with default values.
|
||||
*/
|
||||
PlayerDifficulty::PlayerDifficulty(const std::string &filename)
|
||||
{
|
||||
// Set all other values to undefined, so that it can later be tested
|
||||
// if everything is defined properly.
|
||||
m_mass = m_brake_factor = m_brake_time_increase = m_rescue_time =
|
||||
m_explosion_time = m_explosion_invulnerability_time = m_zipper_time =
|
||||
m_zipper_fade_out_time = m_zipper_force = m_zipper_speed_gain =
|
||||
m_zipper_max_speed_increase = m_rubber_band_max_length =
|
||||
m_rubber_band_force = m_rubber_band_duration =
|
||||
m_rubber_band_speed_increase = m_rubber_band_fade_out_time =
|
||||
m_nitro_consumption = m_nitro_max_speed_increase =
|
||||
m_nitro_engine_force = m_nitro_duration = m_nitro_fade_out_time =
|
||||
m_bubblegum_time = m_bubblegum_torque = m_bubblegum_speed_fraction =
|
||||
m_bubblegum_fade_in_time = m_swatter_duration = m_squash_duration =
|
||||
m_squash_slowdown = m_max_speed_reverse_ratio = m_slipstream_length =
|
||||
m_slipstream_width = m_slipstream_collect_time =
|
||||
m_slipstream_use_time = m_slipstream_add_power =
|
||||
m_slipstream_min_speed = m_slipstream_max_speed_increase =
|
||||
m_slipstream_duration = m_slipstream_fade_out_time = 1;
|
||||
|
||||
m_startup_times.resize(RaceManager::DIFFICULTY_COUNT, 1);
|
||||
m_startup_boost.resize(RaceManager::DIFFICULTY_COUNT, 1);
|
||||
|
||||
// The default constructor for stk_config uses filename=""
|
||||
if (filename != "")
|
||||
load(filename, "normal");
|
||||
} // PlayerDifficulty
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Destructor, dereferences the kart model. */
|
||||
PlayerDifficulty::~PlayerDifficulty()
|
||||
{
|
||||
} // ~PlayerDifficulty
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** */
|
||||
std::string PlayerDifficulty::getIdent() const
|
||||
{
|
||||
switch(m_difficulty)
|
||||
{
|
||||
case PLAYER_DIFFICULTY_NORMAL: return "normal"; break;
|
||||
case PLAYER_DIFFICULTY_HANDICAP: return "handicap"; break;
|
||||
default: assert(false);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Loads the difficulty properties from a file.
|
||||
* \param filename Filename to load.
|
||||
* \param node Name of the xml node to load the data from
|
||||
*/
|
||||
void PlayerDifficulty::load(const std::string &filename, const std::string &node)
|
||||
{
|
||||
const XMLNode* root = new XMLNode(filename);
|
||||
getAllData(root->getNode(node));
|
||||
if(root)
|
||||
delete root;
|
||||
} // load
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Actually reads in the data from the xml file.
|
||||
* \param root Root of the xml tree.
|
||||
*/
|
||||
void PlayerDifficulty::getAllData(const XMLNode * root)
|
||||
{
|
||||
if(const XMLNode *mass_node = root->getNode("mass"))
|
||||
mass_node->get("value", &m_mass);
|
||||
|
||||
if(const XMLNode *engine_node = root->getNode("engine"))
|
||||
{
|
||||
engine_node->get("brake-factor", &m_brake_factor);
|
||||
engine_node->get("brake-time-increase", &m_brake_time_increase);
|
||||
engine_node->get("max-speed-reverse-ratio", &m_max_speed_reverse_ratio);
|
||||
engine_node->get("power", &m_engine_power);
|
||||
engine_node->get("max-speed", &m_max_speed);
|
||||
}
|
||||
|
||||
if(const XMLNode *nitro_node = root->getNode("nitro"))
|
||||
{
|
||||
nitro_node->get("consumption", &m_nitro_consumption );
|
||||
nitro_node->get("max-speed-increase", &m_nitro_max_speed_increase);
|
||||
nitro_node->get("engine-force", &m_nitro_engine_force );
|
||||
nitro_node->get("duration", &m_nitro_duration );
|
||||
nitro_node->get("fade-out-time", &m_nitro_fade_out_time );
|
||||
}
|
||||
|
||||
if(const XMLNode *bubble_node = root->getNode("bubblegum"))
|
||||
{
|
||||
bubble_node->get("time", &m_bubblegum_time );
|
||||
bubble_node->get("speed-fraction", &m_bubblegum_speed_fraction);
|
||||
bubble_node->get("torque", &m_bubblegum_torque );
|
||||
bubble_node->get("fade-in-time", &m_bubblegum_fade_in_time );
|
||||
}
|
||||
|
||||
if(const XMLNode *rescue_node = root->getNode("rescue"))
|
||||
rescue_node->get("time", &m_rescue_time);
|
||||
|
||||
if(const XMLNode *explosion_node = root->getNode("explosion"))
|
||||
{
|
||||
explosion_node->get("time", &m_explosion_time);
|
||||
explosion_node->get("invulnerability-time",
|
||||
&m_explosion_invulnerability_time);
|
||||
}
|
||||
|
||||
if(const XMLNode *slipstream_node = root->getNode("slipstream"))
|
||||
{
|
||||
slipstream_node->get("length", &m_slipstream_length );
|
||||
slipstream_node->get("width", &m_slipstream_width );
|
||||
slipstream_node->get("collect-time", &m_slipstream_collect_time );
|
||||
slipstream_node->get("use-time", &m_slipstream_use_time );
|
||||
slipstream_node->get("add-power", &m_slipstream_add_power );
|
||||
slipstream_node->get("min-speed", &m_slipstream_min_speed );
|
||||
slipstream_node->get("max-speed-increase",
|
||||
&m_slipstream_max_speed_increase);
|
||||
slipstream_node->get("duration", &m_slipstream_duration );
|
||||
slipstream_node->get("fade-out-time", &m_slipstream_fade_out_time );
|
||||
}
|
||||
|
||||
if(const XMLNode *plunger_node= root->getNode("plunger"))
|
||||
{
|
||||
plunger_node->get("band-max-length", &m_rubber_band_max_length );
|
||||
plunger_node->get("band-force", &m_rubber_band_force );
|
||||
plunger_node->get("band-duration", &m_rubber_band_duration );
|
||||
plunger_node->get("band-speed-increase",&m_rubber_band_speed_increase);
|
||||
plunger_node->get("band-fade-out-time", &m_rubber_band_fade_out_time );
|
||||
plunger_node->get("in-face-time", &m_plunger_in_face_duration);
|
||||
}
|
||||
|
||||
if(const XMLNode *zipper_node= root->getNode("zipper"))
|
||||
{
|
||||
zipper_node->get("time", &m_zipper_time );
|
||||
zipper_node->get("fade-out-time", &m_zipper_fade_out_time );
|
||||
zipper_node->get("force", &m_zipper_force );
|
||||
zipper_node->get("speed-gain", &m_zipper_speed_gain );
|
||||
zipper_node->get("max-speed-increase", &m_zipper_max_speed_increase);
|
||||
}
|
||||
|
||||
if(const XMLNode *swatter_node= root->getNode("swatter"))
|
||||
{
|
||||
swatter_node->get("duration", &m_swatter_duration );
|
||||
swatter_node->get("squash-duration", &m_squash_duration );
|
||||
swatter_node->get("squash-slowdown", &m_squash_slowdown );
|
||||
}
|
||||
|
||||
if(const XMLNode *startup_node= root->getNode("startup"))
|
||||
{
|
||||
startup_node->get("time", &m_startup_times);
|
||||
startup_node->get("boost", &m_startup_boost);
|
||||
}
|
||||
} // getAllData
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Called the first time a kart accelerates after 'ready-set-go'. It searches
|
||||
* through m_startup_times to find the appropriate slot, and returns the
|
||||
* speed-boost from the corresponding entry in m_startup_boost.
|
||||
* If the kart started too slow (i.e. slower than the longest time in
|
||||
* m_startup_times, it returns 0.
|
||||
*/
|
||||
float PlayerDifficulty::getStartupBoost() const
|
||||
{
|
||||
float t = World::getWorld()->getTime();
|
||||
for(unsigned int i=0; i<m_startup_times.size(); i++)
|
||||
{
|
||||
if(t<=m_startup_times[i]) return m_startup_boost[i];
|
||||
}
|
||||
return 0;
|
||||
} // getStartupBoost
|
||||
|
@ -1,345 +0,0 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2006-2015 SuperTuxKart-Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#ifndef HEADER_PLAYER_DIFFICULTY_HPP
|
||||
#define HEADER_PLAYER_DIFFICULTY_HPP
|
||||
|
||||
#include "network/remote_kart_info.hpp"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
class XMLNode;
|
||||
|
||||
/**
|
||||
* \brief This class stores values that modify the properties of a kart.
|
||||
* This includes physical properties like speed and the effect of items.
|
||||
* The values stored in this class get multiplied with the current
|
||||
* properties of the kart. If all values here are set to 1, nothing changes.
|
||||
*
|
||||
* \ingroup karts
|
||||
*/
|
||||
class PlayerDifficulty
|
||||
{
|
||||
private:
|
||||
/** Actual difficulty */
|
||||
PerPlayerDifficulty m_difficulty;
|
||||
|
||||
// -----------------
|
||||
/** Weight of kart. */
|
||||
float m_mass;
|
||||
|
||||
/** Maximum force from engine for each difficulty. */
|
||||
float m_engine_power;
|
||||
|
||||
/** Braking factor * engine_power braking force. */
|
||||
float m_brake_factor;
|
||||
|
||||
/** Brake_time * m_brake_time_increase will increase the break time
|
||||
* over time. */
|
||||
float m_brake_time_increase;
|
||||
|
||||
/** Time a kart is moved upwards after when it is rescued. */
|
||||
float m_rescue_time;
|
||||
|
||||
/** Time an animated explosion is shown. Longer = more delay for kart. */
|
||||
float m_explosion_time;
|
||||
|
||||
/** How long a kart is invulnerable after it is hit by an explosion. */
|
||||
float m_explosion_invulnerability_time;
|
||||
|
||||
/** Duration a zipper is active. */
|
||||
float m_zipper_time;
|
||||
|
||||
/** Fade out time for a zipper. */
|
||||
float m_zipper_fade_out_time;
|
||||
|
||||
/** Additional force added to the acceleration. */
|
||||
float m_zipper_force;
|
||||
|
||||
/** Initial one time speed gain. */
|
||||
float m_zipper_speed_gain;
|
||||
|
||||
/** Absolute increase of the kart's maximum speed (in m/s). */
|
||||
float m_zipper_max_speed_increase;
|
||||
|
||||
/** Max. length of plunger rubber band. */
|
||||
float m_rubber_band_max_length;
|
||||
/** Force of an attached rubber band. */
|
||||
/** Duration a rubber band works. */
|
||||
float m_rubber_band_force;
|
||||
/** How long the rubber band will fly. */
|
||||
float m_rubber_band_duration;
|
||||
/** Increase of maximum speed of the kart when the rubber band pulls. */
|
||||
float m_rubber_band_speed_increase;
|
||||
/** Fade out time when the rubber band is removed. */
|
||||
float m_rubber_band_fade_out_time;
|
||||
/**Duration of plunger in face depending on difficulty. */
|
||||
float m_plunger_in_face_duration;
|
||||
/** Nitro consumption. */
|
||||
float m_nitro_consumption;
|
||||
/* How much the speed of a kart might exceed its maximum speed (in m/s). */
|
||||
float m_nitro_max_speed_increase;
|
||||
/** Additional engine force to affect the kart. */
|
||||
float m_nitro_engine_force;
|
||||
/** How long the increased nitro max speed will be valid after
|
||||
* the kart stops using nitro (and the fade-out-time starts). */
|
||||
float m_nitro_duration;
|
||||
/** Duration during which the increased maximum speed
|
||||
* due to nitro fades out. */
|
||||
float m_nitro_fade_out_time;
|
||||
/** Bubble gum diration. */
|
||||
float m_bubblegum_time;
|
||||
/** Torque to add when a bubble gum was hit in order to make the kart go
|
||||
* sideways a bit. */
|
||||
float m_bubblegum_torque;
|
||||
/** Fraction of top speed that can be reached maximum after hitting a
|
||||
* bubble gum. */
|
||||
float m_bubblegum_speed_fraction;
|
||||
/** How long to fade in the slowdown for a bubble gum. */
|
||||
float m_bubblegum_fade_in_time;
|
||||
/** How long the swatter lasts. */
|
||||
float m_swatter_duration;
|
||||
/** How long a kart will remain squashed. */
|
||||
float m_squash_duration;
|
||||
/** The slowdown to apply while a kart is squashed. The new maxspeed
|
||||
* is max_speed*m_squash_slowdown. */
|
||||
float m_squash_slowdown;
|
||||
|
||||
/** The maximum speed at each difficulty. */
|
||||
float m_max_speed;
|
||||
|
||||
float m_max_speed_reverse_ratio;
|
||||
|
||||
/** How far behind a kart slipstreaming is effective. */
|
||||
float m_slipstream_length;
|
||||
/** How wide the slipstream area is at the end. */
|
||||
float m_slipstream_width;
|
||||
/** Time after which sstream gives a bonus. */
|
||||
float m_slipstream_collect_time;
|
||||
/** Time slip-stream bonus is effective. */
|
||||
float m_slipstream_use_time;
|
||||
/** Additional power due to sstreaming. */
|
||||
float m_slipstream_add_power;
|
||||
/** Minimum speed for slipstream to take effect. */
|
||||
float m_slipstream_min_speed;
|
||||
/** How much the speed of the kart might exceed its
|
||||
* normal maximum speed. */
|
||||
float m_slipstream_max_speed_increase;
|
||||
/** How long the higher speed lasts after slipstream stopped working. */
|
||||
float m_slipstream_duration;
|
||||
/** How long the slip stream speed increase will gradually be reduced. */
|
||||
float m_slipstream_fade_out_time;
|
||||
|
||||
/** If the kart starts within the specified time at index I after 'go',
|
||||
* it receives the speed boost from m_startup_boost[I]. */
|
||||
std::vector<float> m_startup_times;
|
||||
|
||||
/** The startup boost is the kart starts fast enough. */
|
||||
std::vector<float> m_startup_boost;
|
||||
|
||||
|
||||
void load (const std::string &filename,
|
||||
const std::string &node);
|
||||
|
||||
|
||||
public:
|
||||
PlayerDifficulty (const std::string &filename="");
|
||||
~PlayerDifficulty ();
|
||||
void getAllData (const XMLNode * root);
|
||||
std::string getIdent() const;
|
||||
float getStartupBoost () const;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the maximum engine power depending on difficulty. */
|
||||
float getMaxPower () const {return m_engine_power; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Get braking information. */
|
||||
float getBrakeFactor () const {return m_brake_factor; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the additional brake factor which depends on time. */
|
||||
float getBrakeTimeIncrease() const { return m_brake_time_increase; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Get maximum reverse speed ratio. */
|
||||
float getMaxSpeedReverseRatio () const
|
||||
{return m_max_speed_reverse_ratio; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the maximum speed dependent on the difficult level. */
|
||||
float getMaxSpeed () const { return m_max_speed; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the nitro consumption. */
|
||||
float getNitroConsumption () const {return m_nitro_consumption; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the increase of maximum speed due to nitro. */
|
||||
float getNitroMaxSpeedIncrease () const
|
||||
{return m_nitro_max_speed_increase; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
float getNitroEngineForce () const {return m_nitro_engine_force; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns how long the increased nitro max speed will be valid after
|
||||
* the kart stops using nitro (and the fade-out-time starts). */
|
||||
float getNitroDuration () const {return m_nitro_duration; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the duration during which the increased maximum speed
|
||||
* due to nitro fades out. */
|
||||
float getNitroFadeOutTime () const {return m_nitro_fade_out_time; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns how long a bubble gum is active. */
|
||||
float getBubblegumTime() const { return m_bubblegum_time; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the torque to add when a bubble gum was hit . */
|
||||
float getBubblegumTorque() const { return m_bubblegum_torque; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the fraction of top speed that can be reached maximum after
|
||||
* hitting a bubble gum. */
|
||||
float getBubblegumSpeedFraction() const {return m_bubblegum_speed_fraction;}
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns how long to fade in the slowdown for a bubble gum. */
|
||||
float getBubblegumFadeInTime() const { return m_bubblegum_fade_in_time; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the time a kart is rised during a rescue. */
|
||||
float getRescueTime () const {return m_rescue_time; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the time an explosion animation is shown. */
|
||||
float getExplosionTime () const {return m_explosion_time; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns how long a kart is invulnerable after being hit by an
|
||||
explosion. */
|
||||
float getExplosionInvulnerabilityTime() const
|
||||
{ return m_explosion_invulnerability_time; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the maximum length of a rubber band before it breaks. */
|
||||
float getRubberBandMaxLength () const {return m_rubber_band_max_length;}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns force a rubber band has when attached to a kart. */
|
||||
float getRubberBandForce () const {return m_rubber_band_force; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the duration a rubber band is active for. */
|
||||
float getRubberBandDuration () const {return m_rubber_band_duration; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the increase of maximum speed while a rubber band is
|
||||
* pulling. */
|
||||
float getRubberBandSpeedIncrease() const
|
||||
{
|
||||
return m_rubber_band_speed_increase;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Return the fade out time once a rubber band is removed. */
|
||||
float getRubberBandFadeOutTime() const
|
||||
{
|
||||
return m_rubber_band_fade_out_time;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns duration of a plunger in your face. */
|
||||
float getPlungerInFaceTime () const {return m_plunger_in_face_duration;}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the time a zipper is active. */
|
||||
float getZipperTime () const {return m_zipper_time; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the time a zipper is active. */
|
||||
float getZipperFadeOutTime () const {return m_zipper_fade_out_time; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the additional force added applied to the kart. */
|
||||
float getZipperForce () const { return m_zipper_force; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the initial zipper speed gain. */
|
||||
float getZipperSpeedGain () const { return m_zipper_speed_gain; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the increase of the maximum speed of the kart
|
||||
* if a zipper is active. */
|
||||
float getZipperMaxSpeedIncrease () const
|
||||
{ return m_zipper_max_speed_increase;}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns how far behind a kart slipstreaming works. */
|
||||
float getSlipstreamLength () const {return m_slipstream_length; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns how wide the slipstream area is at the end. */
|
||||
float getSlipstreamWidth () const {return m_slipstream_width; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns time after which slipstream has maximum effect. */
|
||||
float getSlipstreamCollectTime () const
|
||||
{return m_slipstream_collect_time; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns time after which slipstream has maximum effect. */
|
||||
float getSlipstreamUseTime () const {return m_slipstream_use_time; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns additional power due to slipstreaming. */
|
||||
float getSlipstreamAddPower () const {return m_slipstream_add_power; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the minimum slipstream speed. */
|
||||
float getSlipstreamMinSpeed () const {return m_slipstream_min_speed; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the increase of the maximum speed of a kart
|
||||
* due to slipstream. */
|
||||
float getSlipstreamMaxSpeedIncrease() const
|
||||
{ return m_slipstream_max_speed_increase; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns how long the higher speed lasts after slipstream
|
||||
* stopped working. */
|
||||
float getSlipstreamDuration () const { return m_slipstream_duration; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns how long the slip stream speed increase will gradually
|
||||
* be reduced. */
|
||||
float getSlipstreamFadeOutTime () const
|
||||
{ return m_slipstream_fade_out_time; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns how long a swatter will stay attached/ready to be used. */
|
||||
float getSwatterDuration() const { return m_swatter_duration; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns how long a kart remains squashed. */
|
||||
float getSquashDuration() const {return m_squash_duration; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the slowdown of a kart that is squashed. */
|
||||
float getSquashSlowdown() const {return m_squash_slowdown; }
|
||||
}; // KartProperties
|
||||
|
||||
#endif
|
||||
|
@ -39,8 +39,7 @@ RescueAnimation::RescueAnimation(AbstractKart *kart, bool is_auto_rescue)
|
||||
{
|
||||
m_referee = new Referee(*m_kart);
|
||||
m_kart->getNode()->addChild(m_referee->getSceneNode());
|
||||
m_timer = m_kart->getKartProperties()->getRescueTime() *
|
||||
m_kart->getPlayerDifficulty()->getRescueTime();
|
||||
m_timer = m_kart->getKartProperties()->getRescueDuration();
|
||||
m_velocity = m_kart->getKartProperties()->getRescueHeight() / m_timer;
|
||||
m_xyz = m_kart->getXYZ();
|
||||
|
||||
|
@ -36,7 +36,7 @@
|
||||
|
||||
/** Constructor of the skidding object.
|
||||
*/
|
||||
Skidding::Skidding(Kart *kart, const SkiddingProperties *sp)
|
||||
Skidding::Skidding(Kart *kart)
|
||||
{
|
||||
#ifdef SKID_DEBUG
|
||||
m_predicted_curve = new ShowCurve(0.05f, 0.05f,
|
||||
@ -47,8 +47,8 @@ Skidding::Skidding(Kart *kart, const SkiddingProperties *sp)
|
||||
m_actual_curve->setVisible(false);
|
||||
#endif
|
||||
m_kart = kart;
|
||||
copyFrom(sp);
|
||||
m_skid_reduce_turn_delta = m_skid_reduce_turn_max - m_skid_reduce_turn_min;
|
||||
m_skid_reduce_turn_delta = m_kart->getKartProperties()->getSkidReduceTurnMax()
|
||||
- m_kart->getKartProperties()->getSkidReduceTurnMin();
|
||||
reset();
|
||||
} // Skidding
|
||||
|
||||
@ -95,13 +95,15 @@ void Skidding::reset()
|
||||
*/
|
||||
void Skidding::updateSteering(float steer, float dt)
|
||||
{
|
||||
const KartProperties *kp = m_kart->getKartProperties();
|
||||
|
||||
switch(m_skid_state)
|
||||
{
|
||||
case SKID_SHOW_GFX_LEFT:
|
||||
case SKID_SHOW_GFX_RIGHT:
|
||||
case SKID_NONE:
|
||||
m_real_steering = steer;
|
||||
if(m_skid_time<m_skid_visual_time && m_skid_time>0)
|
||||
if (m_skid_time < kp->getSkidVisualTime() && m_skid_time > 0)
|
||||
{
|
||||
float f = m_visual_rotation - m_visual_rotation*dt/m_skid_time;
|
||||
// Floating point errors when m_skid_time is very close to 0
|
||||
@ -125,25 +127,27 @@ void Skidding::updateSteering(float steer, float dt)
|
||||
case SKID_ACCUMULATE_RIGHT:
|
||||
{
|
||||
float f = (1.0f+steer)*0.5f; // map [-1,1] --> [0, 1]
|
||||
m_real_steering = m_skid_reduce_turn_min+
|
||||
m_skid_reduce_turn_delta*f;
|
||||
if(m_skid_time < m_skid_visual_time)
|
||||
m_visual_rotation = m_skid_visual*m_real_steering*m_skid_time
|
||||
/ m_skid_visual_time;
|
||||
m_real_steering = kp->getSkidReduceTurnMin()
|
||||
+ m_skid_reduce_turn_delta * f;
|
||||
if(m_skid_time < kp->getSkidVisualTime())
|
||||
m_visual_rotation = kp->getSkidVisual()
|
||||
* m_real_steering * m_skid_time
|
||||
/ kp->getSkidVisualTime();
|
||||
else
|
||||
m_visual_rotation = m_skid_visual * m_real_steering;
|
||||
m_visual_rotation = kp->getSkidVisual() * m_real_steering;
|
||||
break;
|
||||
}
|
||||
case SKID_ACCUMULATE_LEFT:
|
||||
{
|
||||
float f = (-1.0f+steer)*0.5f; // map [-1,1] --> [-1, 0]
|
||||
m_real_steering = -m_skid_reduce_turn_min+
|
||||
m_skid_reduce_turn_delta*f;
|
||||
if(m_skid_time < m_skid_visual_time)
|
||||
m_visual_rotation = m_skid_visual*m_real_steering*m_skid_time
|
||||
/ m_skid_visual_time;
|
||||
m_real_steering = -kp->getSkidReduceTurnMin()
|
||||
+ m_skid_reduce_turn_delta * f;
|
||||
if(m_skid_time < kp->getSkidVisualTime())
|
||||
m_visual_rotation = kp->getSkidVisual()
|
||||
* m_real_steering * m_skid_time
|
||||
/ kp->getSkidVisualTime();
|
||||
else
|
||||
m_visual_rotation = m_skid_visual * m_real_steering;
|
||||
m_visual_rotation = kp->getSkidVisual() * m_real_steering;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -173,13 +177,13 @@ float Skidding::getSteeringWhenSkidding(float steering) const
|
||||
break;
|
||||
case SKID_ACCUMULATE_RIGHT:
|
||||
{
|
||||
float f = (steering - m_skid_reduce_turn_min)
|
||||
float f = (steering - m_kart->getKartProperties()->getSkidReduceTurnMin())
|
||||
/ m_skid_reduce_turn_delta;
|
||||
return f *2.0f-1.0f;
|
||||
}
|
||||
case SKID_ACCUMULATE_LEFT:
|
||||
{
|
||||
float f = (steering + m_skid_reduce_turn_min)
|
||||
float f = (steering + m_kart->getKartProperties()->getSkidReduceTurnMin())
|
||||
/ m_skid_reduce_turn_delta;
|
||||
return 2.0f * f +1.0f;
|
||||
}
|
||||
@ -198,6 +202,8 @@ float Skidding::getSteeringWhenSkidding(float steering) const
|
||||
void Skidding::update(float dt, bool is_on_ground,
|
||||
float steering, KartControl::SkidControl skidding)
|
||||
{
|
||||
const KartProperties *kp = m_kart->getKartProperties();
|
||||
|
||||
// If a kart animation is shown, stop all skidding bonuses.
|
||||
if(m_kart->getKartAnimation())
|
||||
{
|
||||
@ -212,7 +218,7 @@ void Skidding::update(float dt, bool is_on_ground,
|
||||
#endif
|
||||
|
||||
// No skidding backwards or while stopped
|
||||
if(m_kart->getSpeed() < m_min_skid_speed &&
|
||||
if(m_kart->getSpeed() < kp->getSkidMinSpeed() &&
|
||||
m_skid_state != SKID_NONE && m_skid_state != SKID_BREAK)
|
||||
{
|
||||
m_skid_state = SKID_BREAK;
|
||||
@ -223,15 +229,16 @@ void Skidding::update(float dt, bool is_on_ground,
|
||||
m_skid_bonus_ready = false;
|
||||
if (is_on_ground)
|
||||
{
|
||||
if((fabs(steering) > 0.001f) &&
|
||||
m_kart->getSpeed()>m_min_skid_speed &&
|
||||
(skidding==KartControl::SC_LEFT||skidding==KartControl::SC_RIGHT))
|
||||
if ((fabs(steering) > 0.001f) &&
|
||||
m_kart->getSpeed() > kp->getSkidMinSpeed() &&
|
||||
(skidding == KartControl::SC_LEFT || skidding == KartControl::SC_RIGHT))
|
||||
{
|
||||
m_skid_factor += m_skid_increase *dt/m_time_till_max_skid;
|
||||
m_skid_factor += kp->getSkidIncrease()
|
||||
* dt / kp->getSkidTimeTillMax();
|
||||
}
|
||||
else if(m_skid_factor>1.0f)
|
||||
else if (m_skid_factor > 1.0f)
|
||||
{
|
||||
m_skid_factor *= m_skid_decrease;
|
||||
m_skid_factor *= kp->getSkidDecrease();
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -239,10 +246,10 @@ void Skidding::update(float dt, bool is_on_ground,
|
||||
m_skid_factor = 1.0f; // Lose any skid factor as soon as we fly
|
||||
}
|
||||
|
||||
if(m_skid_factor>m_skid_max)
|
||||
m_skid_factor = m_skid_max;
|
||||
if (m_skid_factor > kp->getSkidMax())
|
||||
m_skid_factor = kp->getSkidMax();
|
||||
else
|
||||
if(m_skid_factor<1.0f) m_skid_factor = 1.0f;
|
||||
if (m_skid_factor < 1.0f) m_skid_factor = 1.0f;
|
||||
|
||||
// If skidding was started and a graphical jump should still
|
||||
// be displayed, update the data
|
||||
@ -288,8 +295,9 @@ void Skidding::update(float dt, bool is_on_ground,
|
||||
break;
|
||||
// Don't allow skidding while the kart is (apparently)
|
||||
// still in the air, or when the kart is too slow
|
||||
if(m_remaining_jump_time>0 ||
|
||||
m_kart->getSpeed() <m_min_skid_speed) break;
|
||||
if (m_remaining_jump_time > 0 ||
|
||||
m_kart->getSpeed() < kp->getSkidMinSpeed())
|
||||
break;
|
||||
|
||||
m_skid_state = skidding==KartControl::SC_RIGHT
|
||||
? SKID_ACCUMULATE_RIGHT
|
||||
@ -300,14 +308,14 @@ void Skidding::update(float dt, bool is_on_ground,
|
||||
// Then use this speed to determine the impulse necessary to
|
||||
// reach this speed.
|
||||
float v = World::getWorld()->getTrack()->getGravity()
|
||||
* 0.5f*m_physical_jump_time;
|
||||
* 0.5f * kp->getSkidPhysicalJumpTime();
|
||||
btVector3 imp(0, v / m_kart->getBody()->getInvMass(),0);
|
||||
m_kart->getVehicle()->getRigidBody()->applyCentralImpulse(imp);
|
||||
|
||||
// Some karts might use a graphical-only jump. Set it up:
|
||||
m_jump_speed = World::getWorld()->getTrack()->getGravity()
|
||||
* 0.5f*m_graphical_jump_time;
|
||||
m_remaining_jump_time = m_graphical_jump_time;
|
||||
* 0.5f * kp->getSkidGraphicalJumpTime();
|
||||
m_remaining_jump_time = kp->getSkidGraphicalJumpTime();
|
||||
|
||||
#ifdef SKID_DEBUG
|
||||
#define SPEED 20.0f
|
||||
@ -318,13 +326,13 @@ void Skidding::update(float dt, bool is_on_ground,
|
||||
m_predicted_curve->setVisible(true);
|
||||
m_predicted_curve->setPosition(m_kart->getXYZ());
|
||||
m_predicted_curve->setHeading(m_kart->getHeading());
|
||||
float angle = m_kart->getKartProperties()
|
||||
float angle = kp
|
||||
->getMaxSteerAngle(m_kart->getSpeed())
|
||||
* fabsf(getSteeringFraction());
|
||||
angle = m_kart->getKartProperties()
|
||||
angle = kp
|
||||
->getMaxSteerAngle(SPEED)
|
||||
* fabsf(getSteeringFraction());
|
||||
float r = m_kart->getKartProperties()->getWheelBase()
|
||||
float r = kp->getWheelBase()
|
||||
/ asin(angle)*1.0f;
|
||||
|
||||
const int num_steps = 50;
|
||||
@ -335,7 +343,7 @@ void Skidding::update(float dt, bool is_on_ground,
|
||||
{
|
||||
float real_x = m_skid_state==SKID_ACCUMULATE_LEFT ? -x : x;
|
||||
Vec3 xyz(real_x, 0.2f, sqrt(r*r-(r-x)*(r-x))*(1.0f+SPEED/150.0f)
|
||||
*(1+(angle/m_kart->getKartProperties()->getMaxSteerAngle(SPEED)-0.6f)*0.1f));
|
||||
*(1+(angle/kp->getMaxSteerAngle(SPEED)-0.6f)*0.1f));
|
||||
Vec3 xyz1=m_kart->getTrans()(xyz);
|
||||
Log::debug("Skidding", "predict %f %f %f speed %f angle %f",
|
||||
xyz1.getX(), xyz1.getY(), xyz1.getZ(),
|
||||
@ -368,7 +376,7 @@ void Skidding::update(float dt, bool is_on_ground,
|
||||
Log::debug("Skidding", "actual %f %f %f turn %f speed %f angle %f",
|
||||
m_kart->getXYZ().getX(),m_kart->getXYZ().getY(),m_kart->getXYZ().getZ(),
|
||||
m_real_steering, m_kart->getSpeed(),
|
||||
m_kart->getKartProperties()->getMaxSteerAngle(m_kart->getSpeed()));
|
||||
kp->getMaxSteerAngle(m_kart->getSpeed()));
|
||||
#endif
|
||||
m_skid_time += dt;
|
||||
float bonus_time, bonus_speed, bonus_force;
|
||||
@ -388,11 +396,11 @@ void Skidding::update(float dt, bool is_on_ground,
|
||||
m_skid_state = m_skid_state == SKID_ACCUMULATE_LEFT
|
||||
? SKID_SHOW_GFX_LEFT
|
||||
: SKID_SHOW_GFX_RIGHT;
|
||||
float t = std::min(m_skid_time, m_skid_visual_time);
|
||||
t = std::min(t, m_skid_revert_visual_time);
|
||||
float t = std::min(m_skid_time, kp->getSkidVisualTime());
|
||||
t = std::min(t, kp->getSkidRevertVisualTime());
|
||||
|
||||
float vso = getVisualSkidRotation();
|
||||
btVector3 rot(0, vso*m_post_skid_rotate_factor, 0);
|
||||
btVector3 rot(0, vso * kp->getSkidPostSkidRotateFactor(), 0);
|
||||
m_kart->getVehicle()->setTimedRotation(t, rot);
|
||||
// skid_time is used to count backwards for the GFX
|
||||
m_skid_time = t;
|
||||
@ -452,16 +460,19 @@ unsigned int Skidding::getSkidBonus(float *bonus_time,
|
||||
float *bonus_speed,
|
||||
float *bonus_force) const
|
||||
{
|
||||
const KartProperties *kp = m_kart->getKartProperties();
|
||||
|
||||
*bonus_time = 0;
|
||||
*bonus_speed = 0;
|
||||
*bonus_force = 0;
|
||||
for(unsigned int i=0; i<m_skid_bonus_speed.size(); i++)
|
||||
for (unsigned int i = 0; i < kp->getSkidBonusSpeed().size(); i++)
|
||||
{
|
||||
if(m_skid_time<=m_skid_time_till_bonus[i]) return i;
|
||||
*bonus_speed = m_skid_bonus_speed[i];
|
||||
*bonus_time = m_skid_bonus_time[i];
|
||||
*bonus_force = m_skid_bonus_force[i];
|
||||
if (m_skid_time <= kp->getSkidTimeTillBonus()[i])
|
||||
return i;
|
||||
*bonus_speed = kp->getSkidBonusSpeed()[i];
|
||||
*bonus_time = kp->getSkidBonusTime()[i];
|
||||
*bonus_force = kp->getSkidBonusForce()[i];
|
||||
}
|
||||
return (unsigned int) m_skid_bonus_speed.size();
|
||||
return (unsigned int) kp->getSkidBonusSpeed().size();
|
||||
} // getSkidBonusForce
|
||||
|
||||
|
@ -19,7 +19,6 @@
|
||||
#ifndef HEADER_SKIDDING_HPP
|
||||
#define HEADER_SKIDDING_HPP
|
||||
|
||||
#include "karts/skidding_properties.hpp"
|
||||
#include "karts/controller/kart_control.hpp"
|
||||
#include "utils/leak_check.hpp"
|
||||
#include "utils/no_copy.hpp"
|
||||
@ -35,7 +34,7 @@ class ShowCurve;
|
||||
|
||||
#undef SKID_DEBUG
|
||||
|
||||
class Skidding : public SkiddingProperties
|
||||
class Skidding
|
||||
{
|
||||
public:
|
||||
LEAK_CHECK();
|
||||
@ -101,7 +100,7 @@ private:
|
||||
float *bonus_force) const;
|
||||
void updateSteering(float steer, float dt);
|
||||
public:
|
||||
Skidding(Kart *kart, const SkiddingProperties *sp);
|
||||
Skidding(Kart *kart);
|
||||
~Skidding();
|
||||
void reset();
|
||||
void update(float dt, bool is_on_ground, float steer,
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user