#ifndef _CAR_H_
#define _CAR_H_

#include "dr_types.h"

#define CAR_MAX_SIMPLIFICATION_LEVEL 4

extern int gDoing_physics;
extern br_scalar gDt;
extern int gCollision_detection_on__car;                  // suffix added to avoid duplicate symbol
extern br_vector3 gGround_normal__car;                    // suffix added to avoid duplicate symbol
extern void (*ControlCar__car[6])(tCar_spec*, br_scalar); // suffix added to avoid duplicate symbol
extern int gControl__car;                                 // suffix added to avoid duplicate symbol
extern int gFace_num__car;                                // suffix added to avoid duplicate symbol
extern br_angle gOld_yaw__car;                            // suffix added to avoid duplicate symbol
extern br_angle gOld_zoom;
extern br_vector3 gCamera_pos_before_collide;
extern int gMetal_crunch_sound_id__car[5]; // suffix added to avoid duplicate symbol
extern int gMetal_scrape_sound_id__car[3]; // suffix added to avoid duplicate symbol
extern int gCar_car_collisions;
extern int gFreeze_mechanics;
extern tU32 gLast_cunning_stunt;
extern tU32 gWild_start;
extern tU32 gQuite_wild_start;
extern tU32 gQuite_wild_end;
extern tU32 gOn_me_wheels_start;
extern int gWoz_upside_down_at_all;
extern tS3_sound_tag gSkid_tag[2];
extern tCar_spec* gLast_car_to_skid[2];
extern int gEliminate_faces;
extern br_vector3 gZero_v__car; // suffix added to avoid duplicate symbol
extern tU32 gSwitch_time;
extern tSave_camera gSave_camera[2];
extern tU32 gLast_mechanics_time;
extern int gOpponent_viewing_mode;
extern int gNet_player_to_view_index;
extern int gDouble_pling_water;
extern int gStop_opponents_moving;
extern float gDefensive_powerup_factor[6];
extern float gOffensive_powerup_factor[6];
extern float gEngine_powerup_factor[6];
extern br_angle gPanning_camera_angle;
extern br_scalar gPanning_camera_height;
extern int gFace_count;
extern float gCar_simplification_factor[2][5];
extern int gCar_simplification_level;
extern int gNum_active_non_cars;
extern int gCamera_has_collided;
extern tFace_ref gFace_list__car[150]; // suffix added to avoid duplicate symbol
extern tNon_car_spec* gActive_non_car_list[50];
extern int gOver_shoot;
extern br_scalar gMin_world_y;
extern br_scalar gAccel;
extern br_vector3 gAverage_grid_position;
extern br_actor* gPed_actor;
extern int gCollision_count;
extern int gCamera_frozen;
extern int gMaterial_index;
extern int gInTheSea;
extern int gCamera_mode;
extern br_scalar gOur_yaw__car;            // suffix added to avoid duplicate symbol
extern br_scalar gGravity__car;            // suffix added to avoid duplicate symbol
extern br_vector3 gNew_ground_normal__car; // suffix added to avoid duplicate symbol
extern char gNon_car_spec_list[100];
extern tU32 gMechanics_time_sync;
extern int gNum_cars_and_non_cars;

void DamageUnit(tCar_spec* pCar, int pUnit_type, int pDamage_amount);

void DamageUnitWithSmoke(tCar_spec* pCar, int pUnit_type, int pDamage_amount);

void DamageEngine(int pDamage_amount);

void DamageTrans(int pDamage_amount);

void DamageSteering(int pDamage_amount);

void DamageLFWheel(int pDamage_amount);

void DamageLFBrake(int pDamage_amount);

void DamageLRBrake(int pDamage_amount);

void DamageLRWheel(int pDamage_amount);

void DamageRFWheel(int pDamage_amount);

void DamageRFBrake(int pDamage_amount);

void DamageRRBrake(int pDamage_amount);

void DamageRRWheel(int pDamage_amount);

void CalculatePlaneNormal(br_vector3* pP1, br_vector3* pP2, br_vector3* pP3, br_vector3* pNormal);

void CalculateGroundNormal(br_model* pThe_model, int pFace_index);

void ChangeYCoordinate(br_scalar pNew_y, tU32 pTime_taken, br_model* pThe_model, int pFace_index);

void SwitchCarActor(tCar_spec* pCar_spec, int pModel_index);

void InitialiseCar2(tCar_spec* pCar, int pClear_disabled_flag);

void InitialiseCar(tCar_spec* pCar);

void InitialiseCarsEtc(tRace_info* pThe_race);

void GetAverageGridPosition(tRace_info* pThe_race);

void SetInitialPosition(tRace_info* pThe_race, int pCar_index, int pGrid_index);

void SetInitialPositions(tRace_info* pThe_race);

void InitialiseNonCar(tNon_car_spec* non_car);

void GetFacesInBox(tCollision_info* c);

int IsCarInTheSea(void);

void RememberSafePosition(tCar_spec* car, tU32 pTime);

void ControlOurCar(tU32 pTime_difference);

void CalcEngineForce(tCar_spec* c, br_scalar dt);

void PrepareCars(tU32 pFrame_start_time);

void FinishCars(tU32 pLast_frame_time, tU32 pTime);

void InterpolateCars(tU32 pLast_frame_time, tU32 pTime);

void ResetOldmat(void);

void GetNonCars(void);

void GetNetPos(tCar_spec* pCar);

void ApplyPhysicsToCars(tU32 last_frame_time, tU32 pTime_difference);

void MungeSpecialVolume(tCollision_info* pCar);

void ResetCarSpecialVolume(tCollision_info* pCar);

void TestAutoSpecialVolume(tCollision_info* pCar);

void MoveAndCollideCar(tCar_spec* car, br_scalar dt);

void MoveAndCollideNonCar(tNon_car_spec* non_car, br_scalar dt);

int CollideCarWithWall(tCollision_info* car, br_scalar dt);

void ToggleControls(void);

void ControlCar2(tCar_spec* c, br_scalar dt);

void ControlCar3(tCar_spec* c, br_scalar dt);

void ControlCar4(tCar_spec* c, br_scalar dt);

void ControlCar5(tCar_spec* c, br_scalar dt);

void ControlCar1(tCar_spec* c, br_scalar dt);

void setrotate(br_vector3* wdt, br_matrix34* m);

void RotateCar2(tCollision_info* c, br_scalar dt);

void RotateCarSecondOrder(tCollision_info* c, br_scalar dt);

void RotateCarFirstOrder(tCollision_info* c, br_scalar dt);

void SimpleRotate(tCollision_info* c, br_scalar dt);

void RotateCar(tCollision_info* c, br_scalar dt);

void SteeringSelfCentre(tCar_spec* c, br_scalar dt, br_vector3* n);

void NonCarCalcForce(tNon_car_spec* nc, br_scalar dt);

void AddDrag(tCar_spec* c, br_scalar dt);

void DoBumpiness(tCar_spec* c, br_vector3* wheel_pos, br_vector3* norm, br_scalar* d, int n);

void CalcForce(tCar_spec* c, br_scalar dt);

void DoRevs(tCar_spec* c, br_scalar dt);

void ApplyTorque(tCar_spec* c, br_vector3* tdt);

void TranslateCar(tCollision_info* c, br_scalar dt);

int CollCheck(tCollision_info* c, br_scalar dt);

br_scalar AddFriction(tCollision_info* c, br_vector3* vel, br_vector3* normal_force, br_vector3* pos, br_scalar total_force, br_vector3* max_friction);

void AddFrictionCarToCar(tCollision_info* car1, tCollision_info* car2, br_vector3* vel1, br_vector3* vel2, br_vector3* normal_force1, br_vector3* pos1, br_vector3* pos2, br_scalar total_force, br_vector3* max_friction);

void ScrapeNoise(br_scalar vel, br_vector3* position, int material);

void SkidNoise(tCar_spec* pC, int pWheel_num, br_scalar pV, int material);

void StopSkid(tCar_spec* pC);

void CrashNoise(br_vector3* pForce, br_vector3* position, int material);

void CrushAndDamageCar(tCar_spec* c, br_vector3* pPosition, br_vector3* pForce_car_space, tCar_spec* car2);

int ExpandBoundingBox(tCar_spec* c);

void CrushBoundingBox(tCar_spec* c, int crush_only);

void AddCollPoint(br_scalar dist, br_vector3* p, br_vector3* norm, br_vector3* r, br_vector3* n, br_vector3* dir, int num, tCollision_info* c);

br_scalar SinglePointColl(br_scalar* f, br_matrix4* m, br_scalar* d);

br_scalar TwoPointColl(br_scalar* f, br_matrix4* m, br_scalar* d, br_vector3* tau, br_vector3* n);

br_scalar DrMatrix4Inverse(br_matrix4* mi, br_matrix4* mc);

br_scalar ThreePointColl(br_scalar* f, br_matrix4* m, br_scalar* d);

br_scalar ThreePointCollRec(br_scalar* f, br_matrix4* m, br_scalar* d, br_vector3* tau, br_vector3* n, tCollision_info* c);

br_scalar FourPointColl(br_scalar* f, br_matrix4* m, br_scalar* d, br_vector3* tau, br_vector3* n, tCollision_info* c);

void MultiFindFloorInBoxM(int pNum_rays, br_vector3* a, br_vector3* b, br_vector3* nor, br_scalar* d, tCar_spec* c, int* mat_ref);

void MultiFindFloorInBoxBU(int pNum_rays, br_vector3* a, br_vector3* b, br_vector3* nor, br_scalar* d, tCar_spec* c, int* mat_ref);

void findfloor(br_vector3* a, br_vector3* b, br_vector3* nor, br_scalar* d);

int FindFloorInBoxM(br_vector3* a, br_vector3* b, br_vector3* nor, br_scalar* d, tCollision_info* c);

int FindFloorInBoxBU(br_vector3* a, br_vector3* b, br_vector3* nor, br_scalar* d, tCollision_info* c);

int FindFloorInBoxBU2(br_vector3* a, br_vector3* b, br_vector3* nor, br_scalar* d, tCollision_info* c);

int FindFloorInBoxM2(br_vector3* a, br_vector3* b, br_vector3* nor, br_scalar* d, tCollision_info* c);

int BoxFaceIntersect(br_bounds* pB, br_matrix34* pM, br_matrix34* pMold, br_vector3* pPoint_list, br_vector3* pNorm_list, br_scalar* pDist_list, int pMax_pnts, tCollision_info* c);

int AddEdgeCollPoints(br_vector3* p1, br_vector3* p2, br_bounds* pB, br_matrix34* pMold, br_vector3* pPoint_list, br_vector3* pNorm_list, int n, int pMax_pnts, tCollision_info* c);

void GetPlaneNormal(br_vector3* n, int p);

int GetBoundsEdge(br_vector3* pos, br_vector3* edge, br_bounds* pB, int plane1, int plane2, br_vector3* a, br_vector3* b, br_vector3* c, int flag);

void oldMoveOurCar(tU32 pTime_difference);

void ToggleCollisionDetection(void);

void CancelPendingCunningStunt(void);

float frac(float pN);

void SetAmbientPratCam(tCar_spec* pCar);

void MungeCarGraphics(tU32 pFrame_period);

void ResetCarScreens(void);

tCar_spec* GetRaceLeader(void);

void AmIGettingBoredWatchingCameraSpin(void);

void ViewNetPlayer(void);

void ViewOpponent(void);

void ToggleCarToCarCollisions(void);

void SwapCar(void);

void AdjustDownForce(void);

void FreezeMechanics(void);

void PutOpponentsInNeutral(void);

void SetPanningFieldOfView(void);

void CheckDisablePlingMaterials(tCar_spec* pCar);

void PositionExternalCamera(tCar_spec* c, tU32 pTime);

void CameraBugFix(tCar_spec* c, tU32 pTime);

int PossibleRemoveNonCarFromWorld(br_actor* pActor);

void PutNonCarBackInWorld(br_actor* pActor);

int IncidentCam(tCar_spec* c, tU32 pTime);

int MoveCamToIncident(tCar_spec* c, tIncident_type* type, float* severity, tIncident_info* info, tU32* next_incident_time);

void PanningExternalCamera(tCar_spec* c, tU32 pTime);

int CheckForWall(br_vector3* start, br_vector3* end);

void SetUpPanningCamera(tCar_spec* c);

void SaveCameraPosition(int i);

void RestoreCameraPosition(int i);

void NormalPositionExternalCamera(tCar_spec* c, tU32 pTime);

void MoveWithWheels(tCar_spec* c, br_vector3* vn, int manual_swing);

void SwingCamera(tCar_spec* c, br_matrix34* m1, br_matrix34* m2, br_vector3* vn, tU32 pTime);

void PointCameraAtCar(tCar_spec* c, br_matrix34* m1, br_matrix34* m2);

void PointCamera(br_vector3* pos, br_matrix34* m2);

int CollideCamera2(br_vector3* car_pos, br_vector3* cam_pos, br_vector3* old_camera_pos, int manual_move);

int BoundsTest(br_bounds* bnds, br_vector3* p);

int CollideCameraWithOtherCars(br_vector3* car_pos, br_vector3* cam_pos);

void InitialiseExternalCamera(void);

void FreezeCamera(void);

void FlyCar(tCar_spec* c, br_scalar dt);

void DrVector3RotateY(br_vector3* v, br_angle t);

void CrashCarsTogether(br_scalar dt);

int CrashCarsTogetherSinglePass(br_scalar dt, int pPass, tCollison_data* collide_list);

void BringCarToAGrindingHalt(tCollision_info* car);

int BoundsOverlapTest_car(br_bounds* b1, br_bounds* b2);

int SimpleCarCarCollisionTest(tCollision_info* car1, tCollision_info* car2);

int CollideTwoCarsWithWalls(tCollision_info* car1, tCollision_info* car2, br_scalar dt);

int CollideTwoCarsRepeatedly(tCollision_info* car1, tCollision_info* car2, br_scalar dt);

int CollideTwoCars(tCollision_info* car1, tCollision_info* car2, int pPass);

int GetEdgeEdgeCollisions(br_bounds* pB1, br_bounds* pB2, br_matrix34* pM21, br_matrix34* pM12, br_matrix34* pMo21, br_matrix34* pMo12, br_matrix34* pM1o1, br_vector3* pPoint_list, br_vector3* pNorm_list, int pMax);

int FacePointCarCarCollide(tCollision_info* car1, tCollision_info* car2, br_matrix34* pMms, br_matrix34* pMoms, br_matrix34* pMsos, br_vector3* pPoint_list, br_vector3* pNorm_list, int pMax, int order);

void MungeCarsMass(tCollision_info* pCar, br_scalar pFactor);

void ModifyCarsMass(tCollision_info* pCar_1, tCollision_info* pCar_2);

void ResetCarsMass(tCollision_info* pCar_1, tCollision_info* pCar_2);

int DoCollide(tCollision_info* car1, tCollision_info* car2, br_vector3* r, br_vector3* n, int k, int pPass, br_matrix34* mat1_to_mat2);

br_scalar TwoPointCollB(br_scalar* f, br_matrix4* m, br_scalar* d, br_vector3* tau, br_vector3* n);

br_scalar ThreePointCollRecB(br_scalar* f, br_matrix4* m, br_scalar* d, br_vector3* tau, br_vector3* n);

br_scalar FourPointCollB(br_scalar* f, br_matrix4* m, br_scalar* d, br_vector3* tau, br_vector3* n);

int TestForNan(float* f);

void CheckCameraHither(void);

void SetCarSuspGiveAndHeight(tCar_spec* pCar, br_scalar pFront_give_factor, br_scalar pRear_give_factor, br_scalar pDamping_factor, br_scalar pExtra_front_height, br_scalar pExtra_rear_height);

int TestForCarInSensiblePlace(tCar_spec* car);

int TestOldMats(tCollision_info* c1, tCollision_info* c2, int newmats);

int PullActorFromWorld(br_actor* pActor);

int DoPullActorFromWorld(br_actor* pActor);

void CheckForDeAttachmentOfNonCars(tU32 pTime);

void AdjustNonCar(br_actor* pActor, br_matrix34* pMat);

void PipeSingleNonCar(tCollision_info* c);

int GetPrecalculatedFacesUnderCar(tCar_spec* pCar, tFace_ref** pFace_refs);

br_material* SomeNearbyMaterial(void);

#endif
