/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * 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, see <http://www.gnu.org/licenses/>.
 *
 */

#include "twine/scene/buggy.h"
#include "twine/audio/sound.h"
#include "twine/scene/actor.h"
#include "twine/scene/animations.h"
#include "twine/scene/collision.h"
#include "twine/scene/movements.h"
#include "twine/scene/scene.h"
#include "twine/shared.h"
#include "twine/twine.h"

#define MAX_SAMPLE_PITCH 11000
#define MIN_SAMPLE_PITCH2 5000
#define MAX_SAMPLE_PITCH2 8500
#define MAX_SPEED 3800
#define TEMPO_GEAR 1200 // speed change
#define SAMPLE_BUGGY 109

namespace TwinE {

void Buggy::initBuggy(uint8 numobj, uint32 flaginit) {
	S_BUGGY *ptb = &ListBuggy[0];
	ActorStruct *ptrobj = _engine->_scene->getActor(numobj);

	// So that the objects follow their tracks without being interrupted
	// by the buggy (too bad, it will be pushed)
	ptrobj->_flags.bCanBePushed = true;
	ptrobj->_flags.bCanDrown = true;

	if (flaginit == 2               // we force the repositioning of the buggy
		|| (flaginit && !NumBuggy)) // first initialization
									// because the empty buggy cannot be Twinsen
	{
		ptb->Cube = _engine->_scene->_numCube; // Port-Ludo (Desert)

		ptb->X = ptrobj->_posObj.x;
		ptb->Y = ptrobj->_posObj.y;
		ptb->Z = ptrobj->_posObj.z;

		ptb->Beta = ptrobj->_beta;

		_engine->_actor->initBody(BodyType::btNormal, numobj);

		NumBuggy = (uint8)(numobj | BUGGY_PRESENT);
	} else if (NumBuggy) {
		if (_engine->_scene->getActor(OWN_ACTOR_SCENE_INDEX)->_move != ControlMode::kBuggyManual && _engine->_scene->getActor(OWN_ACTOR_SCENE_INDEX)->_move != ControlMode::kBuggy) {
			int32 x, y;

			if (_engine->_scene->_numCube == ptb->Cube) {
				ptrobj->_posObj.x = ptb->X;
				ptrobj->_posObj.y = ptb->Y;
				ptrobj->_posObj.z = ptb->Z;

				ptrobj->_beta = ptb->Beta;

				_engine->_actor->initBody(BodyType::btNormal, numobj);
			} else if (_engine->_scene->loadSceneCubeXY(ptb->Cube, &x, &y)) {
				x -= _engine->_scene->_currentCubeX;
				y -= _engine->_scene->_currentCubeY;

				ptrobj->_posObj.x = ptb->X + x * 32768;
				ptrobj->_posObj.y = ptb->Y;
				ptrobj->_posObj.z = ptb->Z + y * 32768;

				ptrobj->_beta = ptb->Beta;

				ptrobj->_flags.bNoShadow = 1;
				ptrobj->_flags.bIsBackgrounded = 1;
				ptrobj->_flags.bNoElectricShock = 1;
				ptrobj->_flags.bHasZBuffer = 1;

				_engine->_actor->initBody(BodyType::btNormal, numobj);
			} else {
				_engine->_actor->initBody(BodyType::btNone, numobj);
			}

			_engine->_movements->clearRealAngle(ptrobj);
		} else {
			_engine->_actor->initBody(BodyType::btNone, numobj);
		}

		NumBuggy = (uint8)(numobj | BUGGY_PRESENT);
	} else {
		_engine->_actor->initBody(BodyType::btNone, numobj);
	}
}

void Buggy::resetBuggy() {
	S_BUGGY *ptb = &ListBuggy[0];

	NumBuggy = 0;
	ptb->Cube = 0;
}

void Buggy::takeBuggy() {
	int32 sample;
	ActorStruct *ptrobj = _engine->_scene->getActor(OWN_ACTOR_SCENE_INDEX);
	S_BUGGY *ptb = &ListBuggy[0];

	ptb->SpeedRot = 1024;
	// TODO: ptb->LastTimer = TimerRefHR;

	// TODO: ObjectClear(&ptrobj);

	// Shielding in case the Buggy moved (being pushed, for example).
	ptb->X = _engine->_scene->getActor(NUM_BUGGY)->_posObj.x;
	ptb->Y = _engine->_scene->getActor(NUM_BUGGY)->_posObj.y;
	ptb->Z = _engine->_scene->getActor(NUM_BUGGY)->_posObj.z;

	ptrobj->_posObj.x = ptb->X;
	ptrobj->_posObj.y = ptb->Y;
	ptrobj->_posObj.z = ptb->Z;
	ptrobj->_beta = ptb->Beta;
	_engine->_movements->clearRealAngle(ptrobj); // To avoid crushing the beta.

	ptrobj->_workFlags.bMANUAL_INTER_FRAME = true;
	ptrobj->_flags.bHasZBuffer = true;

	// TODO: _engine->_actor->setBehaviour(HeroBehaviourType::kBUGGY);

	// Switch Buggy Scenario to NoBody.
	_engine->_actor->initBody(BodyType::btNone, NUM_BUGGY);

	if (ptrobj->SampleAlways) {
		_engine->_sound->stopSample(ptrobj->SampleAlways);
		ptrobj->SampleAlways = 0;
	}

	sample = SAMPLE_BUGGY;

	if (_engine->_sound->isSamplePlaying(sample)) {
		_engine->_sound->stopSample(sample);
	}

	ptrobj->SampleVolume = 20;

	// TODO: ParmSampleVolume = ptrobj->SampleVolume;

	Gear = 0;
	TimerGear = 0;

	// TODO: ptrobj->SampleAlways = _engine->_sound->playSample(SAMPLE_BUGGY, 4096, 0, 0,
	//    ptrobj->_posObj.x, ptrobj->_posObj.y, ptrobj->_posObj.z);
}

#if 0
static void ObjectClear(T_OBJ *ptb3d) {
	memset(ptb3d, 0, sizeof(T_OBJ));
	ptb3d.OBJ_3D.Body, -1
	ptb3d.OBJ_3D.NextBody, -1
	ptb3d.OBJ_3D.Texture, -1
	ptb3d.OBJ_3D.NextTexture, -1
	ptb3d.OBJ_3D.Anim, -1
}
#endif

void Buggy::leaveBuggy(HeroBehaviourType behaviour) {
	int32 sample;
	ActorStruct *ptrobj = _engine->_scene->getActor(OWN_ACTOR_SCENE_INDEX);
	S_BUGGY *ptb = &ListBuggy[0];

	sample = SAMPLE_BUGGY;

	if (_engine->_sound->isSamplePlaying(sample)) {
		_engine->_sound->stopSample(sample);
		ptrobj->SampleAlways = 0;
	}

	ptb->X = ptrobj->_posObj.x;
	ptb->Y = ptrobj->_posObj.y;
	ptb->Z = ptrobj->_posObj.z;
	ptb->Beta = ptrobj->_beta;
	ptb->Cube = _engine->_scene->_numCube;

	// TODO: ObjectClear(ptrobj);

	ptrobj->_workFlags.bMANUAL_INTER_FRAME = 0;
	ptrobj->_flags.bHasZBuffer = 0;

	_engine->_actor->initBody(BodyType::btTunic, OWN_ACTOR_SCENE_INDEX);

	_engine->_actor->setBehaviour(behaviour);

	// Restore scenario buggy.

	ptrobj = _engine->_scene->getActor(NUM_BUGGY);

	ptrobj->_posObj.x = ptb->X;
	ptrobj->_posObj.y = ptb->Y;
	ptrobj->_posObj.z = ptb->Z;
	ptrobj->_beta = ptb->Beta;

	ptrobj->_brickSound = _engine->_scene->getActor(OWN_ACTOR_SCENE_INDEX)->_brickSound;

	_engine->_movements->clearRealAngle(ptrobj); // To avoid crushing the beta

	_engine->_actor->initBody(BodyType::btNormal, NUM_BUGGY);

	// Search for a free position for Twinsen nearby.
	_engine->_actor->posObjectAroundAnother(NUM_BUGGY, OWN_ACTOR_SCENE_INDEX);
}

#if 0

struct T_HALF_POLY {
	uint32 Bank : 4;       // coul bank poly
	uint32 TexFlag : 2;    // flag texture 00 rien 01 triste 10 flat 11 gouraud
	uint32 PolyFlag : 2;   // flag poly 00 rien 01 flat 10 gouraud 11 dither
	uint32 SampleStep : 4; // sample pas twinsen
	uint32 CodeJeu : 4;    // code jeu
	uint32 Sens : 1;       // sens diagonale
	uint32 Col : 1;
	uint32 Dummy : 1;
	uint32 IndexTex : 13; // index texture 8192
}; // 1 long

struct T_HALF_TEX {
	uint16 Tx0;
	uint16 Ty0;
	uint16 Tx1;
	uint16 Ty1;
	uint16 Tx2;
	uint16 Ty2;
}; // 2 Longs

int32 CalculAltitudeObjet(int32 x, int32 z, int32 cj) {
	int32 y0, y1, y2, y3;
	int32 dx, dz;
	int32 dz0, dz1;

	dx = x >> 9; // div512
	dz = z >> 9; // div512

	if ((dx < 0) || (dx > 63))
		return -1;
	if ((dz < 0) || (dz > 63))
		return -1;

	x &= 511;
	z &= 511;

	dz0 = dz * 65;
	dz1 = dz0 + 65;

	//---------------------------------------------------------------
	if (cj == -1) {
		T_HALF_POLY *mappoly = &MapPolyGround[dz * 64 * 2 + dx * 2];

		if (mappoly->Sens == 0) // poly séparé par ligne reliant point 0 et 2
		{
			if (x >= z) // poly de droite
			{
				mappoly++;
			}
		} else // poly séparé par ligne reliant point 1 et 3
		{
			if (511 - x <= z) // poly de droite
			{
				mappoly++;
			}
		}

		cj = (uint8)mappoly->CodeJeu;
	}
	//--------------------------------------------------------------

	y0 = MapSommetY[dz0 + dx];
	y1 = MapSommetY[dz1 + dx];
	y2 = MapSommetY[dz1 + (dx + 1)];
	y3 = MapSommetY[dz0 + (dx + 1)];

	if (cj == CJ_FOOT_WATER OR cj == CJ_WATER) {
		uint8 *i = &MapIntensity[dz0 + dx];

		y0 += (i[0] >> 4) * -200;
		y1 += (i[65] >> 4) * -200;
		y2 += (i[65 + 1] >> 4) * -200;
		y3 += (i[1] >> 4) * -200;
	}
	if (MapPolyGround[dz * 64 * 2 + dx * 2].Sens == 0) // poly séparé par ligne reliant point 0 et 2
	{
		if (x < z) // poly de gauche
		{
			return (y0 + ((y1 - y0) * z + (y2 - y1) * x) / 512);
		} else // poly de droite
		{
			return (y0 + ((y3 - y0) * x + (y2 - y3) * z) / 512);
		}
	} else // poly séparé par ligne reliant point 1 et 3
	{
		if (511 - x > z) // poly de gauche
		{
			return (y0 + ((y3 - y0) * x + (y1 - y0) * z) / 512);
		} else // poly de droite
		{
			return (y1 + ((y2 - y1) * x + (y3 - y2) * (511 - z)) / 512);
		}
	}
}
#endif

void Buggy::doAnimBuggy(ActorStruct *ptrobj) {
#if 0
	int32 x1, y1, z1, yw;
	S_BUGGY *ptb = &ListBuggy[0];
	T_OBJ_3D *ptb3d = &ptrobj->Obj;

	// wheels rot
	int32 c, d;

	int32 x, y, z;

	// Trick to avoid crushing the groups in AffOneObject().
	ObjectSetInterFrame(ptb3d);

	if (ptrobj->_workFlags.bIsFalling || ptrobj->_workFlags.bANIM_MASTER_GRAVITY) {
		return;
	}

	LongRotate(0, ptb->SpeedInc * 1024, ptb3d->Beta);
	ptrobj->_processActor.x = ptb3d->X + X0 / 1024;
	ptrobj->_processActor.z = ptb3d->Z + Z0 / 1024;

	// Ideal altitude
	yw = CalculAltitudeObjet(ptrobj->_processActor.x, ptrobj->_processActor.z, -1); // Ground Y for XZ

	// test altitude #2: Forbidden triangles

	// Front left wheel direction
	ptb3d->CurrentFrame[3].Beta = (int16)ptb->BetaWheel;
	// Front right wheel direction
	ptb3d->CurrentFrame[6].Beta = (int16)ptb->BetaWheel;

	// Management of 4 separate wheels.

	// front right wheel

	LongRotate(-400, 400, ptb3d->Beta);
	x = ptrobj->_processActor.x + X0;
	z = ptrobj->_processActor.z + Z0;
	y = yw;

	if (x >= 0 && x < 32768 && z >= 0 && z < 32768) {
		y += CalculAltitudeObjet(x, z, -1);
	}

	c = (260 * 31415) / 1000; // Circumference * 10
	d = Distance3D(ptb->Wheel[0].X, ptb->Wheel[0].Y, ptb->Wheel[0].Z, x, y, z);

	if (ptb->Speed >= 0) {
		ptb->Wheel[0].Angle += (4096 * 10 * d) / c;
	} else {
		ptb->Wheel[0].Angle -= (4096 * 10 * d) / c;
	}

	ptb->Wheel[0].X = x;
	ptb->Wheel[0].Y = y;
	ptb->Wheel[0].Z = z;

	// front left wheel

	LongRotate(400, 400, ptb3d->Beta);
	x = ptrobj->_processActor.x + X0;
	z = ptrobj->_processActor.z + Z0;
	y = yw;

	if (x >= 0 && x < 32768 && z >= 0 && z < 32768) {
		y += CalculAltitudeObjet(x, z, -1);
	}

	c = (260 * 31415) / 1000; // Circumference * 10
	d = Distance3D(ptb->Wheel[1].X, ptb->Wheel[1].Y, ptb->Wheel[1].Z, x, y, z);

	if (ptb->Speed >= 0) {
		ptb->Wheel[1].Angle += (4096 * 10 * d) / c;
	} else {
		ptb->Wheel[1].Angle -= (4096 * 10 * d) / c;
	}

	ptb->Wheel[1].X = x;
	ptb->Wheel[1].Y = y;
	ptb->Wheel[1].Z = z;

	// back left wheel

	LongRotate(400, -350, ptb3d->Beta);
	x = ptrobj->_processActor.x + X0;
	z = ptrobj->_processActor.z + Z0;
	y = yw;

	if (x >= 0 && x < 32768 && z >= 0 && z < 32768) {
		y += CalculAltitudeObjet(x, z, -1);
	}

	c = (360 * 31415) / 1000; // Circumference * 10
	d = Distance3D(ptb->Wheel[2].X, ptb->Wheel[2].Y, ptb->Wheel[2].Z, x, y, z);

	if (ptb->Speed >= 0) {
		ptb->Wheel[2].Angle += (4096 * 10 * d) / c;
	} else {
		ptb->Wheel[2].Angle -= (4096 * 10 * d) / c;
	}

	ptb->Wheel[2].X = x;
	ptb->Wheel[2].Y = y;
	ptb->Wheel[2].Z = z;

	// back right wheel

	LongRotate(-400, -350, ptb3d->Beta);
	x = ptrobj->_processActor.x + X0;
	z = ptrobj->_processActor.z + Z0;
	y = yw;

	if (x >= 0 && x < 32768 && z >= 0 && z < 32768) {
		y += CalculAltitudeObjet(x, z, -1);
	}

	c = (360 * 31415) / 1000; // Circumference * 10
	d = Distance3D(ptb->Wheel[3].X, ptb->Wheel[3].Y, ptb->Wheel[3].Z, x, y, z);

	if (ptb->Speed >= 0) {
		ptb->Wheel[3].Angle += (4096 * 10 * d) / c;
	} else {
		ptb->Wheel[3].Angle -= (4096 * 10 * d) / c;
	}

	ptb->Wheel[3].X = x;
	ptb->Wheel[3].Y = y;
	ptb->Wheel[3].Z = z;

	// front right wheel
	ptb3d->CurrentFrame[4].Alpha = (int16)ptb->Wheel[1].Angle;
	// front left wheel
	ptb3d->CurrentFrame[7].Alpha = (int16)ptb->Wheel[0].Angle;
	// back left wheel
	ptb3d->CurrentFrame[11].Alpha = (int16)ptb->Wheel[2].Angle;
	// back right wheel
	ptb3d->CurrentFrame[9].Alpha = (int16)ptb->Wheel[3].Angle;

	// Car inclination (pitch)
	ptb3d->CurrentFrame[1].Type = 0;

	LongRotate(0, 400, ptb3d->Beta);
	x1 = X0;
	z1 = Z0;
	LongRotate(0, -400, ptb3d->Beta);

	if (Nxw + x1 >= 0 && Nxw + x1 < 32768 && Nzw + z1 >= 0 && Nzw + z1 < 32768) {
		y = CalculAltitudeObjet(Nxw + x1, Nzw + z1, -1);
	} else {
		y = yw;
	}

	if (Nxw + X0 >= 0 && Nxw + X0 < 32768 && Nzw + Z0 >= 0 && Nzw + Z0 < 32768) {
		y1 = CalculAltitudeObjet(Nxw + X0, Nzw + Z0, -1);
	} else {
		y1 = yw;
	}

	ptb3d->CurrentFrame[1].Alpha = (int16)(1024 - GetAngle2D(0, y, 800, y1));
	ptb->Alpha = ptb3d->CurrentFrame[1].Alpha;

	// Car inclination (roll)
	LongRotate(400, 0, ptb3d->Beta);
	x1 = X0;
	z1 = Z0;
	LongRotate(-400, 0, ptb3d->Beta);

	if (Nxw + X0 >= 0 && Nxw + X0 < 32768 && Nzw + Z0 >= 0 && Nzw + Z0 < 32768) {
		y = CalculAltitudeObjet(Nxw + X0, Nzw + Z0, -1);
	} else {
		y = yw;
	}

	if (Nxw + x1 >= 0 && Nxw + x1 < 32768 && Nzw + z1 >= 0 && Nzw + z1 < 32768) {
		y1 = CalculAltitudeObjet(Nxw + x1, Nzw + z1, -1);
	} else {
		y1 = yw;
	}

	ptb3d->CurrentFrame[1].Gamma = (int16)GetAngle2D(y, 0, y1, 800);

	// Steering wheel
	ptb3d->CurrentFrame[12].Gamma = (int16)-ptb->BetaWheel;

	// Twinsen's head
	ptb3d->CurrentFrame[14].Beta = (int16)ptb->BetaWheel;
#endif
}

void Buggy::moveBuggy(ActorStruct *ptrobj) {
#if 0
	S_BUGGY *ptb = &ListBuggy[0];
	T_OBJ_3D *ptb3d = &ptrobj->Obj;
	int32 pitch = 0;
	int32 flagattack = false;

	int32 speedinc;
	int32 rotlevel;
	int32 timerhr, deltatimer;

	timerhr = TimerRefHR;
	deltatimer = timerhr - ptb->LastTimer;

	if ((Input & I_THROW) && (PtrComportement->Flags & CF_WEAPON)) {
		// Are we in mage?
		if (TabInv[FLAG_TUNIQUE].IdObj3D == 0) {
			_engine->_actor->initBody(BodyType::btTunicTir, OWN_ACTOR_SCENE_INDEX);
		} else {
			_engine->_actor->initBody(BodyType::btMageTir, OWN_ACTOR_SCENE_INDEX);
		}

		_engine->_animations->initAnim(AnimationTypes::kThrowBall, AnimType::kAnimationTypeRepeat, OWN_ACTOR_SCENE_INDEX);

		/* control direction pendant Aiming */
		if (!ptrobj->_workFlags.bIsRotationByAnim) {
			ptb3d->Beta += GetDeltaMove(&ptrobj->BoundAngle.Move);
			ptb3d->Beta &= 4095;

			_engine->_movements->initRealAngleConst(ptrobj);
		}

		_engine->_movements->_lastJoyFlag = true;
		flagattack = true;
	} else {
		if (LastInput & I_THROW) {
			// We finished shooting with the buggy,
			// we close the hood
			_engine->_actor->initBody(BodyType::btTunic, OWN_ACTOR_SCENE_INDEX);
			_engine->_animations->initAnim(AnimationTypes::kStanding, AnimType::kAnimationTypeRepeat, OWN_ACTOR_SCENE_INDEX);
		}
	}

	if (!flagattack && !ptrobj->_workFlags.bIsFalling && !ptrobj->_workFlags.bANIM_MASTER_GRAVITY) {
		_engine->_movements->clearRealAngle(ptrobj);

		if (_engine->_movements->_lastJoyFlag && (((Input & I_JOY) != LastMyJoy) || ((Input & I_FIRE) != LastMyFire))) {
			_engine->_animations->initAnim(AnimationTypes::kStanding, AnimType::kAnimationTypeRepeat, OWN_ACTOR_SCENE_INDEX);
			Pushing = false;
		}

		_engine->_movements->_lastJoyFlag = false;

		// Pushing contains the number of the object being pushed
		// So 1000 is an impossible value used as an initialization flag
		// no animation
		if (Pushing == 1000) {
			_engine->_animations->initAnim(AnimationTypes::kStanding, AnimType::kAnimationTypeRepeat, OWN_ACTOR_SCENE_INDEX);
			Pushing = false;
		}

		if (Input & I_UP) {
			if (Pushing) {
				_engine->_animations->initAnim(AnimationTypes::kPush, ANIM_TEMPO, OWN_ACTOR_SCENE_INDEX);
				_engine->_movements->_lastJoyFlag = true;
			} else {
				_engine->_animations->initAnim(AnimationTypes::kForward, AnimType::kAnimationTypeRepeat, OWN_ACTOR_SCENE_INDEX);
				_engine->_movements->_lastJoyFlag = true;
			}
		} else if (Input & I_DOWN) {
			_engine->_animations->initAnim(AnimationTypes::kBackward, AnimType::kAnimationTypeRepeat, OWN_ACTOR_SCENE_INDEX);
			_engine->_movements->_lastJoyFlag = true;
		}
	}

	if (!ptrobj->_workFlags.bIsFalling && !ptrobj->_workFlags.bANIM_MASTER_GRAVITY) {
		// check speed command
		if ((Input & I_UP) // accelerating
			&& !flagattack) {
			ptb->Speed += deltatimer * 4;

			if (!TimerGear)
				TimerGear = TimerRefHR + TEMPO_GEAR;
			else {
				if (Gear < 0)
					Gear = 0;

				if (TimerRefHR > TimerGear && Gear < 2) {
					Gear++;
					TimerGear = TimerRefHR + TEMPO_GEAR;
				}
			}
		} else if ((Input & I_DOWN) // brake / reverse
				   && !flagattack) {
			ptb->Speed -= deltatimer * 12;
			Gear = -1;
			TimerGear = 0;
		} else // slow down
		{
			if (ptb->Speed > 0) {
				ptb->Speed -= deltatimer * 7;
				if (ptb->Speed < 0) {
					ptb->Speed = 0;
				}
			}
			if (ptb->Speed < 0) {
				ptb->Speed += deltatimer * 7;
				if (ptb->Speed > 0) {
					ptb->Speed = 0;
				}
			}
			Gear = 0;
			TimerGear = 0;
		}

		if (ptb->Speed < -2000)
			ptb->Speed = -2000;
		if (ptb->Speed > MAX_SPEED)
			ptb->Speed = MAX_SPEED;

		speedinc = ptb->Speed * deltatimer / 1000;
	} else {
		speedinc = 0;
	}

	// check dir

	if (!flagattack) {
		if (Input & I_RIGHT) {
			ptb->BetaWheel = -300;
			if (ptb->Speed) {
				rotlevel = -ptb->SpeedRot * speedinc / ptb->Speed;
			} else {
				rotlevel = 0;
			}
		} else if (Input & I_LEFT) {
			ptb->BetaWheel = 300;
			if (ptb->Speed) {
				rotlevel = ptb->SpeedRot * speedinc / ptb->Speed;
			} else {
				rotlevel = 0;
			}
		} else {
			ptb->BetaWheel = 0;
			rotlevel = 0;
		}

		if (ptrobj->_staticFlags.bSKATING) {
			ptb->Speed = 3000;
			speedinc = ptb->Speed * deltatimer / 1000;
		} else {
			if (ptb->Speed >= 0) {
				ptb3d->Beta += rotlevel;
			} else {
				ptb3d->Beta -= rotlevel;
			}

			ptb3d->Beta = ClampAngle(ptb3d->Beta);
		}
	} else {
		ptb->BetaWheel = 0;
	}

	LastMyJoy = Input & I_JOY;
	LastMyFire = Input & I_FIRE;
	LastInput = Input;

	ptb->LastTimer = timerhr;
	ptb->SpeedInc = speedinc;

	if (ptrobj->SampleAlways && _engine->_sound->isSamplePlaying(ptrobj->SampleAlways)) {
		int32 pitch;

		switch (Gear) {
		case -1:
			pitch = boundRuleThree(3000, MAX_SAMPLE_PITCH2, MAX_SPEED, ABS(ptb->Speed));
			break;

		case 0:
			pitch = boundRuleThree(3000, MAX_SAMPLE_PITCH, MAX_SPEED, ABS(ptb->Speed));
			if (pitch >= MAX_SAMPLE_PITCH)
				TimerGear = 1;
			break;

		case 1:
			pitch = boundRuleThree(MAX_SAMPLE_PITCH2, MIN_SAMPLE_PITCH2, TEMPO_GEAR, TimerGear - TimerRefHR);
			break;

		default:
			pitch = MAX_SAMPLE_PITCH2;
		}

		_engine->_sound->ChangePitchbendSample(ptrobj->SampleAlways, pitch);
	}
#endif
}

} // namespace TwinE
