code:
#pragma once
#include "PathFind.h"
#include "Boat.h"
#include "Vehicle.h"

#define GAME_SPEED_TO_METERS_PER_SECOND 50.0f
#define METERS_PER_SECOND_TO_GAME_SPEED (1.0f / GAME_SPEED_TO_METERS_PER_SECOND)
#define GAME_SPEED_TO_CARAI_SPEED 60.0f
#define TIME_COPS_WAIT_TO_EXIT_AFTER_STOPPING 2500

class CZoneInfo;

enum{
	MAX_CARS_TO_KEEP = 2,
	MAX_CAR_MODELS_IN_ARRAY = 256,
};

#define LANE_WIDTH 5.0f

#ifdef FIX_BUGS
#define FIX_PATHFIND_BUG
#endif

class CCarCtrl
{
public:
	enum eCarClass {
		POOR = 0,
		RICH,
		EXEC,
		WORKER,
		SPECIAL,
		BIG,
		TAXI,
		TOTAL_CUSTOM_CLASSES,
		MAFIA,
		TRIAD,
		DIABLO,
		YAKUZA,
		YARDIE,
		COLOMB,
		NINES,
		GANG8,
		GANG9,
		COPS
	};

	static void SwitchVehicleToRealPhysics(CVehicle*);
	static void AddToCarArray(int32 id, int32 vehclass);
	static void UpdateCarCount(CVehicle*, bool);
	static int32 ChooseCarModel(int32 vehclass);
	static bool JoinCarWithRoadSystemGotoCoors(CVehicle*, CVector, bool);
	static void JoinCarWithRoadSystem(CVehicle*);
	static void UpdateCarOnRails(CVehicle*);
	static bool MapCouldMoveInThisArea(float x, float y);
	static void ScanForPedDanger(CVehicle *veh);
	static void RemoveFromInterestingVehicleList(CVehicle*);
	static void GenerateRandomCars(void);
	static void GenerateOneRandomCar(void);
	static void GenerateEmergencyServicesCar(void);
	static int32 ChooseModel(CZoneInfo*, CVector*, int*);
	static int32 ChoosePoliceCarModel(void);
	static int32 ChooseGangCarModel(int32 gang);
	static void RemoveDistantCars(void);
	static void PossiblyRemoveVehicle(CVehicle*);
	static bool IsThisVehicleInteresting(CVehicle*);
	static void RegisterVehicleOfInterest(CVehicle*);
	static int32 CountCarsOfType(int32 mi);
	static void SlowCarOnRailsDownForTrafficAndLights(CVehicle*);
	static bool PickNextNodeAccordingStrategy(CVehicle*);
	static void DragCarToPoint(CVehicle*, CVector*);
	static float FindMaximumSpeedForThisCarInTraffic(CVehicle*);
	static void SlowCarDownForCarsSectorList(CPtrList&, CVehicle*, float, float, float, float, float*, float);
	static void SlowCarDownForPedsSectorList(CPtrList&, CVehicle*, float, float, float, float, float*, float);
	static void SlowCarDownForOtherCar(CEntity*, CVehicle*, float*, float);
	static float TestCollisionBetween2MovingRects(CVehicle*, CVehicle*, float, float, CVector*, CVector*, uint8);
	static float FindAngleToWeaveThroughTraffic(CVehicle*, CPhysical*, float, float);
	static void WeaveThroughCarsSectorList(CPtrList&, CVehicle*, CPhysical*, float, float, float, float, float*, float*);
	static void WeaveForOtherCar(CEntity*, CVehicle*, float*, float*);
	static void WeaveThroughPedsSectorList(CPtrList&, CVehicle*, CPhysical*, float, float, float, float, float*, float*);
	static void WeaveForPed(CEntity*, CVehicle*, float*, float*);
	static void WeaveThroughObjectsSectorList(CPtrList&, CVehicle*, float, float, float, float, float*, float*);
	static void WeaveForObject(CEntity*, CVehicle*, float*, float*);
#ifdef FIX_PATHFIND_BUG
	static void PickNextNodeToChaseCar(CVehicle*, float, float, float, CVehicle*);
#else
	static void PickNextNodeToChaseCar(CVehicle*, float, float, CVehicle*);
#endif
	static bool PickNextNodeToFollowPath(CVehicle*);
	static void PickNextNodeRandomly(CVehicle*);
	static uint8 FindPathDirection(int32, int32, int32);
	static void Init(void);
	static void ReInit(void);
	static float FindSpeedMultiplier(float, float, float, float);
	static void SteerAICarWithPhysics(CVehicle*);
	static void SteerAICarWithPhysics_OnlyMission(CVehicle*, float*, float*, float*, bool*);
	static void SteerAIBoatWithPhysics(CBoat*);
	static float FindMaxSteerAngle(CVehicle*);
	static void SteerAICarWithPhysicsFollowPath(CVehicle*, float*, float*, float*, bool*);
	static void SteerAICarWithPhysicsHeadingForTarget(CVehicle*, CPhysical*, float, float, float*, float*, float*, bool*);
	static void SteerAICarWithPhysicsTryingToBlockTarget(CVehicle*, float, float, float, float, float*, float*, float*, bool*);
	static void SteerAICarWithPhysicsTryingToBlockTarget_Stop(CVehicle*, float, float, float, float, float*, float*, float*, bool*);
	static void SteerAIBoatWithPhysicsHeadingForTarget(CBoat*, float, float, float*, float*, float*);
	static bool ThisRoadObjectCouldMove(int16);
	static void ClearInterestingVehicleList();
	static void FindLinksToGoWithTheseNodes(CVehicle*);
	static bool GenerateOneEmergencyServicesCar(uint32, CVector);

	static float GetPositionAlongCurrentCurve(CVehicle* pVehicle)
	{
		uint32 timeInCurve = CTimer::GetTimeInMilliseconds() - pVehicle->AutoPilot.m_nTimeEnteredCurve;
		return (float)timeInCurve / pVehicle->AutoPilot.m_nTimeToSpendOnCurrentCurve;
	}

	static float LimitRadianAngle(float angle)
	{
		while (angle < -PI)
			angle += TWOPI;
		while (angle > PI)
			angle -= TWOPI;
		return angle;
	}

	static int32 NumLawEnforcerCars;
	static int32 NumAmbulancesOnDuty;
	static int32 NumFiretrucksOnDuty;
	static int32 NumRandomCars;
	static int32 NumMissionCars;
	static int32 NumParkedCars;
	static int32 NumPermanentCars;
	static bool bCarsGeneratedAroundCamera;
	static float CarDensityMultiplier;
	static int8 CountDownToCarsAtStart;
	static int32 MaxNumberOfCarsInUse;
	static uint32 LastTimeLawEnforcerCreated;
	static uint32 LastTimeFireTruckCreated;
	static uint32 LastTimeAmbulanceCreated;
	static int32 TotalNumOfCarsOfRating[TOTAL_CUSTOM_CLASSES];
	static int32 NextCarOfRating[TOTAL_CUSTOM_CLASSES];
	static int32 CarArrays[TOTAL_CUSTOM_CLASSES][MAX_CAR_MODELS_IN_ARRAY];
};

extern CVehicle* apCarsToKeep[MAX_CARS_TO_KEEP];

license: mit


code:
#include "common.h"

#include "Curves.h"

float CCurves::CalcSpeedScaleFactor(CVector* pPoint1, CVector* pPoint2, float dir1X, float dir1Y, float dir2X, float dir2Y)
{
	CVector2D dir1(dir1X, dir1Y);
	CVector2D dir2(dir2X, dir2Y);
	float distance = (*pPoint1 - *pPoint2).Magnitude2D();
	float dp = DotProduct2D(dir1, dir2);
	if (dp > 0.9f)
		return distance + Abs((pPoint1->x * dir1Y - pPoint1->y * dir1X) - (pPoint2->x * dir1Y - pPoint2->y * dir1X));
	else
		return ((1.0f - dp) * 0.2f + 1.0f) * distance;
}

void CCurves::CalcCurvePoint(CVector* pPos1, CVector* pPos2, CVector* pDir1, CVector* pDir2, float between, int32 timeOnCurve, CVector* pOutPos, CVector* pOutDir)
{
	float actualFactor = CalcSpeedScaleFactor(pPos1, pPos2, pDir1->x, pDir1->y, pDir2->x, pDir2->y);
	CVector2D dir1 = *pDir1 * actualFactor;
	CVector2D dir2 = *pDir2 * actualFactor;
	float curveCoef = 0.5f - 0.5f * Cos(3.1415f * between);
	*pOutPos = CVector(
		(pPos1->x + between * dir1.x) * (1.0f - curveCoef) + (pPos2->x - (1 - between) * dir2.x) * curveCoef,
		(pPos1->y + between * dir1.y) * (1.0f - curveCoef) + (pPos2->y - (1 - between) * dir2.y) * curveCoef,
		0.0f);
	*pOutDir = CVector(
		(dir1.x * (1.0f - curveCoef) + dir2.x * curveCoef) / (timeOnCurve * 0.001f),
		(dir1.y * (1.0f - curveCoef) + dir2.y * curveCoef) / (timeOnCurve * 0.001f),
		0.0f);
}


code:
#pragma once
class CVector;

class CCurves
{
public:
	static float CalcSpeedScaleFactor(CVector*, CVector*, float, float, float, float);
	static void CalcCurvePoint(CVector*, CVector*, CVector*, CVector*, float, int32, CVector*, CVector*);
};


code:
#include "common.h"

#include "main.h"
#include "Darkel.h"
#include "PlayerPed.h"
#include "Wanted.h"
#include "Timer.h"
#include "DMAudio.h"
#include "Population.h"
#include "Weapon.h"
#include "World.h"
#include "Stats.h"
#include "Font.h"
#include "Text.h"
#include "Vehicle.h"
#ifdef FIX_BUGS
#include "Replay.h"
#endif

#define FRENZY_ANY_PED -1
#define FRENZY_ANY_CAR -2

int32 CDarkel::TimeLimit;
int32 CDarkel::PreviousTime;
int32 CDarkel::TimeOfFrenzyStart;
int32 CDarkel::WeaponType;
int32 CDarkel::AmmoInterruptedWeapon;
int32 CDarkel::KillsNeeded;
int8 CDarkel::InterruptedWeapon;

/*
 * bStandardSoundAndMessages is a completely beta thing,
 * makes game handle sounds & messages instead of SCM (just like in GTA2)
 * but it's never been used in the game. Has unused sliding text when frenzy completed etc.
 */
bool CDarkel::bStandardSoundAndMessages;
bool CDarkel::bNeedHeadShot;
bool CDarkel::bProperKillFrenzy;
uint16 CDarkel::Status;
uint16 CDarkel::RegisteredKills[NUM_DEFAULT_MODELS];
int32 CDarkel::ModelToKill;
int32 CDarkel::ModelToKill2;
int32 CDarkel::ModelToKill3;
int32 CDarkel::ModelToKill4;
wchar *CDarkel::pStartMessage;

uint8
CDarkel::CalcFade(uint32 time, uint32 start, uint32 end)
{
	if (time >= start && time <= end) {
		if (time >= start + 500) {
			if (time <= end - 500)
				return 255;
			else
				return 255 * (end - time) / 500;
		} else
			return 255 * (time - start) / 500;
	} else
		return 0;
}

// Screen positions taken from VC
void
CDarkel::DrawMessages()
{
#ifdef FIX_BUGS
	if (CReplay::IsPlayingBack())
		return;
#endif
	switch (Status) {
		case KILLFRENZY_ONGOING:
		{
			CFont::SetJustifyOff();
			CFont::SetBackgroundOff();
#ifdef FIX_BUGS
			CFont::SetCentreSize(SCREEN_SCALE_X(DEFAULT_SCREEN_WIDTH - 30));
#else
			CFont::SetCentreSize(SCREEN_WIDTH - 30);
#endif
			CFont::SetCentreOn();
			CFont::SetPropOn();
			uint32 timePassedSinceStart = CTimer::GetTimeInMilliseconds() - CDarkel::TimeOfFrenzyStart;
			if (CDarkel::bStandardSoundAndMessages) {
				if (timePassedSinceStart >= 3000 && timePassedSinceStart < 11000) {
#ifdef FIX_BUGS
					CFont::SetScale(SCREEN_SCALE_X(1.3f), SCREEN_SCALE_Y(1.3f));
#else
					CFont::SetScale(1.3f, 1.3f);
#endif
					CFont::SetJustifyOff();
					CFont::SetColor(CRGBA(255, 255, 128, CalcFade(timePassedSinceStart, 3000, 11000)));
					CFont::SetFontStyle(FONT_BANK);
					if (pStartMessage) {
						CFont::PrintString(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, pStartMessage);
					}
				}
			} else {
				if (timePassedSinceStart < 8000) {
#ifdef FIX_BUGS
					CFont::SetScale(SCREEN_SCALE_X(1.3f), SCREEN_SCALE_Y(1.3f));
#else
					CFont::SetScale(1.3f, 1.3f);
#endif
					CFont::SetJustifyOff();
					CFont::SetColor(CRGBA(255, 255, 128, CalcFade(timePassedSinceStart, 0, 8000)));
					CFont::SetFontStyle(FONT_BANK);
					if (pStartMessage) {
						CFont::PrintString(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, pStartMessage);
					}
				}
			}
#ifdef FIX_BUGS
			CFont::SetScale(SCREEN_SCALE_X(0.75f), SCREEN_SCALE_Y(1.5f));
#else
			CFont::SetScale(0.75f, 1.5f);
#endif
			CFont::SetCentreOff();
			CFont::SetRightJustifyOn();
			CFont::SetFontStyle(FONT_HEADING);
			if (CDarkel::TimeLimit >= 0) {
				uint32 timeLeft = CDarkel::TimeLimit - (CTimer::GetTimeInMilliseconds() - CDarkel::TimeOfFrenzyStart);
				sprintf(gString, "%d:%02d", timeLeft / 60000, timeLeft % 60000 / 1000);
				AsciiToUnicode(gString, gUString);
				if (timeLeft > 4000 || CTimer::GetFrameCounter() & 1) {
					CFont::SetColor(CRGBA(0, 0, 0, 255));
#if defined(PS2_HUD) || defined(FIX_BUGS)
	#ifdef FIX_BUGS
					CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(34.0f - 1.0f), SCREEN_SCALE_Y(108.0f + 1.0f), gUString);
	#else
					CFont::PrintString(SCREEN_WIDTH-(34.0f - 1.0f), 108.0f + 1.0f, gUString);
	#endif
#else
					CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(34.0f + 1.0f), SCREEN_SCALE_Y(108.0f + 1.0f), gUString);
#endif
					CFont::SetColor(CRGBA(150, 100, 255, 255));
					CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(34.0f), SCREEN_SCALE_Y(108.0f), gUString);
				}
			}
			sprintf(gString, "%d", (CDarkel::KillsNeeded >= 0 ? CDarkel::KillsNeeded : 0));
			AsciiToUnicode(gString, gUString);
			CFont::SetColor(CRGBA(0, 0, 0, 255));
#ifdef FIX_BUGS
#define DARKEL_COUNTER_HEIGHT 143.0f
#else
#define DARKEL_COUNTER_HEIGHT 128.0f
#endif

#if defined(PS2_HUD) || defined(FIX_BUGS)
	#ifdef FIX_BUGS
		    CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(34.0f - 1.0f), SCREEN_SCALE_Y(DARKEL_COUNTER_HEIGHT + 1.0f), gUString);
	#else
		    CFont::PrintString(SCREEN_WIDTH-(34.0f - 1.0f), DARKEL_COUNTER_HEIGHT + 1.0f, gUString);
	#endif
#else
		    CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(34.0f + 1.0f), SCREEN_SCALE_Y(DARKEL_COUNTER_HEIGHT + 1.0f), gUString);
#endif
			CFont::SetColor(CRGBA(255, 128, 128, 255));
		    CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(34.0f), SCREEN_SCALE_Y(DARKEL_COUNTER_HEIGHT), gUString);
#undef DARKEL_COUNTER_HEIGHT
			break;
		}
		case KILLFRENZY_PASSED:
		{
			if (CDarkel::bStandardSoundAndMessages) {
				uint32 timePassedSinceStart = CTimer::GetTimeInMilliseconds() - CDarkel::TimeOfFrenzyStart;
				if (CTimer::GetTimeInMilliseconds() - CDarkel::TimeOfFrenzyStart < 5000) {
					CFont::SetBackgroundOff();
#ifdef FIX_BUGS
					CFont::SetCentreSize(SCREEN_SCALE_X(DEFAULT_SCREEN_WIDTH - 20));
#else
					CFont::SetCentreSize(SCREEN_WIDTH - 20);
#endif
					CFont::SetCentreOn();
#ifdef FIX_BUGS
					CFont::SetScale(SCREEN_SCALE_X(1.5f), SCREEN_SCALE_Y(1.5f));
#else
					CFont::SetScale(1.5f, 1.5f);
#endif
					CFont::SetJustifyOff();
					CFont::SetColor(CRGBA(128, 255, 128, CalcFade(timePassedSinceStart, 0, 5000)));
					CFont::SetFontStyle(FONT_BANK);
#ifdef FIX_BUGS
					int y = SCREEN_HEIGHT / 2 + SCREEN_SCALE_Y(25.0f - timePassedSinceStart * 0.01f);
#else
					int y = (SCREEN_HEIGHT / 2 + 25) - (timePassedSinceStart * 0.01f);
#endif
					CFont::PrintString(SCREEN_WIDTH / 2, y, TheText.Get("KF_3"));
				}
			}
			break;
		}
		default:
			break;
	}
}

void
CDarkel::Init()
{
	Status = KILLFRENZY_NONE;
}

uint16
CDarkel::QueryModelsKilledByPlayer(int32 modelId)
{
	return RegisteredKills[modelId];
}

bool
CDarkel::FrenzyOnGoing()
{
	return Status == KILLFRENZY_ONGOING;
}

uint16
CDarkel::ReadStatus()
{
	return Status;
}

void
CDarkel::RegisterCarBlownUpByPlayer(CVehicle *vehicle)
{
#ifdef FIX_BUGS
	if (CReplay::IsPlayingBack())
		return;
#endif
	if (FrenzyOnGoing()) {
		int32 model = vehicle->GetModelIndex();
		if (ModelToKill == FRENZY_ANY_CAR || ModelToKill == model || ModelToKill2 == model || ModelToKill3 == model || ModelToKill4 == model) {
			KillsNeeded--;
			DMAudio.PlayFrontEndSound(SOUND_RAMPAGE_CAR_BLOWN, 0);
		}
	}
	RegisteredKills[vehicle->GetModelIndex()]++;
	CStats::CarsExploded++;
}

void
CDarkel::RegisterKillByPlayer(CPed *victim, eWeaponType weapon, bool headshot)
{
#ifdef FIX_BUGS
	if (CReplay::IsPlayingBack())
		return;
#endif
	if (FrenzyOnGoing() && (weapon == WeaponType
			|| weapon == WEAPONTYPE_EXPLOSION
			|| weapon == WEAPONTYPE_UZI_DRIVEBY && WeaponType == WEAPONTYPE_UZI
			|| weapon == WEAPONTYPE_RAMMEDBYCAR && WeaponType == WEAPONTYPE_RUNOVERBYCAR
			|| weapon == WEAPONTYPE_RUNOVERBYCAR && WeaponType == WEAPONTYPE_RAMMEDBYCAR
			|| weapon == WEAPONTYPE_FLAMETHROWER && WeaponType == WEAPONTYPE_MOLOTOV)) {
		int32 model = victim->GetModelIndex();
		if (ModelToKill == FRENZY_ANY_PED || ModelToKill == model || ModelToKill2 == model || ModelToKill3 == model || ModelToKill4 == model) {
			if (!bNeedHeadShot || headshot) {
				KillsNeeded--;
				DMAudio.PlayFrontEndSound(SOUND_RAMPAGE_KILL, 0);
			}
		}
	}
	CStats::PeopleKilledByPlayer++;
	RegisteredKills[victim->GetModelIndex()]++;
	CStats::PedsKilledOfThisType[victim->bChrisCriminal ? PEDTYPE_CRIMINAL : victim->m_nPedType]++;
	if (headshot)
		CStats::HeadsPopped++;
	CStats::KillsSinceLastCheckpoint++;
}

void
CDarkel::RegisterKillNotByPlayer(CPed* victim, eWeaponType weapontype)
{
#ifdef FIX_BUGS
	if (CReplay::IsPlayingBack())
		return;
#endif
	CStats::PeopleKilledByOthers++;
}

void
CDarkel::ResetModelsKilledByPlayer()
{
	for (int i = 0; i < NUM_DEFAULT_MODELS; i++)
		RegisteredKills[i] = 0;
}

void
CDarkel::ResetOnPlayerDeath()
{
	if (Status != KILLFRENZY_ONGOING)
		return;

	CPopulation::m_AllRandomPedsThisType = -1;
	Status = KILLFRENZY_FAILED;
	TimeOfFrenzyStart = CTimer::GetTimeInMilliseconds();

	eWeaponType fixedWeapon;
	if (WeaponType == WEAPONTYPE_UZI_DRIVEBY)
		fixedWeapon = WEAPONTYPE_UZI;
	else
		fixedWeapon = (eWeaponType)WeaponType;

	CPlayerPed *player = FindPlayerPed();
	if (fixedWeapon < WEAPONTYPE_TOTALWEAPONS) {
		player->m_nSelectedWepSlot = InterruptedWeapon;
		player->GetWeapon(player->GetWeaponSlot(fixedWeapon)).m_nAmmoTotal = CDarkel::AmmoInterruptedWeapon;
	}

	if (FindPlayerVehicle()) {
		player->RemoveWeaponModel(CWeaponInfo::GetWeaponInfo(player->GetWeapon()->m_eWeaponType)->m_nModelId);
		player->m_currentWeapon = player->m_nSelectedWepSlot;
		player->MakeChangesForNewWeapon(player->m_currentWeapon);
	}
}

void
CDarkel::StartFrenzy(eWeaponType weaponType, int32 time, uint16 kill, int32 modelId0, wchar *text, int32 modelId2, int32 modelId3, int32 modelId4, bool standardSound, bool needHeadShot)
{
	eWeaponType fixedWeapon;
	if (weaponType == WEAPONTYPE_UZI_DRIVEBY)
		fixedWeapon = WEAPONTYPE_UZI;
	else
		fixedWeapon = weaponType;

	WeaponType = weaponType;
	Status = KILLFRENZY_ONGOING;
	KillsNeeded = kill;
	ModelToKill = modelId0;
	ModelToKill2 = modelId2;
	ModelToKill3 = modelId3;
	ModelToKill4 = modelId4;
	pStartMessage = text;

	if (text == TheText.Get("PAGE_00")) {
		CDarkel::bProperKillFrenzy = true;
		CDarkel::pStartMessage = nil;
	} else
		bProperKillFrenzy = false;

	bStandardSoundAndMessages = standardSound;
	bNeedHeadShot = needHeadShot;
	TimeOfFrenzyStart = CTimer::GetTimeInMilliseconds();
	TimeLimit = time;
	PreviousTime = time / 1000;

	CPlayerPed *player = FindPlayerPed();
	if (fixedWeapon < WEAPONTYPE_TOTALWEAPONS) {
		InterruptedWeapon = player->m_currentWeapon;
		player->GiveWeapon(fixedWeapon, 0);
		AmmoInterruptedWeapon = player->GetWeapon(player->GetWeaponSlot(fixedWeapon)).m_nAmmoTotal;
		player->GiveWeapon(fixedWeapon, 30000);
		player->m_nSelectedWepSlot = player->GetWeaponSlot(fixedWeapon);
		player->MakeChangesForNewWeapon(player->m_nSelectedWepSlot);

		if (FindPlayerVehicle()) {
			player->m_currentWeapon = player->m_nSelectedWepSlot;
			player->GetWeapon()->m_nAmmoInClip = Min(player->GetWeapon()->m_nAmmoTotal, CWeaponInfo::GetWeaponInfo(player->GetWeapon()->m_eWeaponType)->m_nAmountofAmmunition);
			player->ClearWeaponTarget();
		}
	}
	if (CDarkel::bStandardSoundAndMessages)
		DMAudio.PlayFrontEndSound(SOUND_RAMPAGE_START, 0);
}

void
CDarkel::Update()
{
#ifdef FIX_BUGS
	if (CReplay::IsPlayingBack())
		return;
#endif

	if (Status != KILLFRENZY_ONGOING)
		return;

	int32 FrameTime = TimeLimit - (CTimer::GetTimeInMilliseconds() - TimeOfFrenzyStart);
	if (FrameTime > 0 || TimeLimit < 0) {

		DMAudio.PlayFrontEndSound(SOUND_RAMPAGE_ONGOING, FrameTime);

		int32 PrevTime = FrameTime / 1000;

		if (PrevTime != PreviousTime) {
			if (PreviousTime < 12)
				DMAudio.PlayFrontEndSound(SOUND_CLOCK_TICK, PrevTime);
			PreviousTime = PrevTime;
		}

	} else {
		CPopulation::m_AllRandomPedsThisType = -1;
		Status = KILLFRENZY_FAILED;
		TimeOfFrenzyStart = CTimer::GetTimeInMilliseconds();

		eWeaponType fixedWeapon;
		if (WeaponType == WEAPONTYPE_UZI_DRIVEBY)
			fixedWeapon = WEAPONTYPE_UZI;
		else
			fixedWeapon = (eWeaponType)WeaponType;

		CPlayerPed *player = FindPlayerPed();
		if (fixedWeapon < WEAPONTYPE_TOTALWEAPONS) {
			player->m_nSelectedWepSlot = InterruptedWeapon;
			player->GetWeapon(player->GetWeaponSlot(fixedWeapon)).m_nAmmoTotal = CDarkel::AmmoInterruptedWeapon;
		}

		if (FindPlayerVehicle()) {
			player->RemoveWeaponModel(CWeaponInfo::GetWeaponInfo(player->GetWeapon()->m_eWeaponType)->m_nModelId);
			player->m_currentWeapon = player->m_nSelectedWepSlot;
			player->MakeChangesForNewWeapon(player->m_currentWeapon);
		}

		if (bStandardSoundAndMessages)
			DMAudio.PlayFrontEndSound(SOUND_RAMPAGE_FAILED, 0);
	}

	if (KillsNeeded <= 0) {
		CPopulation::m_AllRandomPedsThisType = -1;
		Status = KILLFRENZY_PASSED;

		if (bProperKillFrenzy)
			CStats::AnotherKillFrenzyPassed();

		TimeOfFrenzyStart = CTimer::GetTimeInMilliseconds();

		FindPlayerPed()->m_pWanted->SetWantedLevel(0);

		eWeaponType fixedWeapon;
		if (WeaponType == WEAPONTYPE_UZI_DRIVEBY)
			fixedWeapon = WEAPONTYPE_UZI;
		else
			fixedWeapon = (eWeaponType)WeaponType;

		CPlayerPed* player = FindPlayerPed();
		if (fixedWeapon < WEAPONTYPE_TOTALWEAPONS) {
			player->m_nSelectedWepSlot = InterruptedWeapon;
			player->GetWeapon(player->GetWeaponSlot(fixedWeapon)).m_nAmmoTotal = CDarkel::AmmoInterruptedWeapon;
		}

		if (FindPlayerVehicle()) {
			player->RemoveWeaponModel(CWeaponInfo::GetWeaponInfo(player->GetWeapon()->m_eWeaponType)->m_nModelId);
			player->m_currentWeapon = player->m_nSelectedWepSlot;
			player->MakeChangesForNewWeapon(player->m_currentWeapon);
		}

		if (bStandardSoundAndMessages)
			DMAudio.PlayFrontEndSound(SOUND_RAMPAGE_PASSED, 0);
	}
}


code:
#pragma once

#include "ModelIndices.h"
#include "WeaponType.h"

class CVehicle;
class CPed;

enum
{
	KILLFRENZY_NONE,
	KILLFRENZY_ONGOING,
	KILLFRENZY_PASSED,
	KILLFRENZY_FAILED,
};

class CDarkel
{
private:
	static int32 TimeLimit;
	static int32 PreviousTime;
	static int32 TimeOfFrenzyStart;
	static int32 WeaponType;
	static int32 AmmoInterruptedWeapon;
	static int32 KillsNeeded;
	static int8 InterruptedWeapon;
	static bool bStandardSoundAndMessages;
	static bool bNeedHeadShot;
	static bool bProperKillFrenzy;
	static uint16 Status;
	static uint16 RegisteredKills[NUM_DEFAULT_MODELS];
	static int32 ModelToKill;
	static int32 ModelToKill2;
	static int32 ModelToKill3;
	static int32 ModelToKill4;
	static wchar *pStartMessage;

public:
	static uint8 CalcFade(uint32 time, uint32 min, uint32 max);
	static void DrawMessages(void);
	static bool FrenzyOnGoing();
	static void Init();
	static uint16 QueryModelsKilledByPlayer(int32 modelId);
	static uint16 ReadStatus();
	static void RegisterCarBlownUpByPlayer(CVehicle *vehicle);
	static void RegisterKillByPlayer(CPed *victim, eWeaponType weapontype, bool headshot = false);
	static void RegisterKillNotByPlayer(CPed* victim, eWeaponType weapontype);
	static void ResetModelsKilledByPlayer();
	static void ResetOnPlayerDeath();
	static void StartFrenzy(eWeaponType weaponType, int32 time, uint16 kill, int32 modelId0, wchar *text, int32 modelId2, int32 modelId3, int32 modelId4, bool standardSound, bool needHeadShot);
	static void Update();

};


code:
#include "common.h"

#include "GameLogic.h"
#include "Clock.h"
#include "Stats.h"
#include "Pickups.h"
#include "Timer.h"
#include "Streaming.h"
#include "CutsceneMgr.h"
#include "World.h"
#include "PlayerPed.h"
#include "Wanted.h"
#include "Camera.h"
#include "Messages.h"
#include "CarCtrl.h"
#include "Restart.h"
#include "Pad.h"
#include "References.h"
#include "Fire.h"
#include "Script.h"
#include "Garages.h"
#include "screendroplets.h"

uint8 CGameLogic::ActivePlayers;

void
CGameLogic::InitAtStartOfGame()
{
	ActivePlayers = 1;
}

void
CGameLogic::PassTime(uint32 time)
{
	int32 minutes, hours, days;

	minutes = time + CClock::GetMinutes();
	hours = CClock::GetHours();

	for (; minutes >= 60; minutes -= 60)
		hours++;

	if (hours > 23) {
		days = CStats::DaysPassed;
		for (; hours >= 24; hours -= 24)
			days++;
		CStats::DaysPassed = days;
	}

	CClock::SetGameClock(hours, minutes);
	CPickups::PassTime(time * 1000);
}

void
CGameLogic::SortOutStreamingAndMemory(const CVector &pos)
{
	CTimer::Stop();
	CStreaming::FlushRequestList();
	CStreaming::DeleteRwObjectsAfterDeath(pos);
	CStreaming::RemoveUnusedModelsInLoadedList();
	CGame::DrasticTidyUpMemory(true);
	CStreaming::LoadScene(pos);
	CTimer::Update();
}

void
CGameLogic::Update()
{
	CVector vecRestartPos;
	float fRestartFloat;

	if (CCutsceneMgr::IsCutsceneProcessing()) return;

	CPlayerInfo &pPlayerInfo = CWorld::Players[CWorld::PlayerInFocus];
	switch (pPlayerInfo.m_WBState) {
	case WBSTATE_PLAYING:
		if (pPlayerInfo.m_pPed->m_nPedState == PED_DEAD) {
			pPlayerInfo.m_pPed->ClearAdrenaline();
			pPlayerInfo.KillPlayer();
		}
		if (pPlayerInfo.m_pPed->m_nPedState == PED_ARRESTED) {
			pPlayerInfo.m_pPed->ClearAdrenaline();
			pPlayerInfo.ArrestPlayer();
		}
		break;
	case WBSTATE_WASTED:
#ifdef MISSION_REPLAY
		if ((CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime > AddExtraDeathDelay() + 0x800) && (CTimer::GetPreviousTimeInMilliseconds() - pPlayerInfo.m_nWBTime <= AddExtraDeathDelay() + 0x800)) {
#else
		if ((CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime > 0x800) && (CTimer::GetPreviousTimeInMilliseconds() - pPlayerInfo.m_nWBTime <= 0x800)) {
#endif
			TheCamera.SetFadeColour(200, 200, 200);
			TheCamera.Fade(2.0f, FADE_OUT);
		}

#ifdef MISSION_REPLAY
		if (CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime >= AddExtraDeathDelay() + 0x1000) {
#else
		if (CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime >= 0x1000) {
#endif
			pPlayerInfo.m_WBState = WBSTATE_PLAYING;
			if (pPlayerInfo.m_bGetOutOfHospitalFree) {
				pPlayerInfo.m_bGetOutOfHospitalFree = false;
			} else {
				pPlayerInfo.m_nMoney = Max(0, pPlayerInfo.m_nMoney - 1000);
				pPlayerInfo.m_pPed->ClearWeapons();
			}

			if (pPlayerInfo.m_pPed->bInVehicle) {
				CVehicle *pVehicle = pPlayerInfo.m_pPed->m_pMyVehicle;
				if (pVehicle != nil) {
					if (pVehicle->pDriver == pPlayerInfo.m_pPed) {
						pVehicle->pDriver = nil;
						if (pVehicle->GetStatus() != STATUS_WRECKED)
							pVehicle->SetStatus(STATUS_ABANDONED);
					} else
						pVehicle->RemovePassenger(pPlayerInfo.m_pPed);
				}
			}
			CEventList::Initialise();
#ifdef SCREEN_DROPLETS
			ScreenDroplets::Initialise();
#endif
			CMessages::ClearMessages();
			CCarCtrl::ClearInterestingVehicleList();
			CWorld::ClearExcitingStuffFromArea(pPlayerInfo.GetPos(), 4000.0f, 1);
			CRestart::FindClosestHospitalRestartPoint(pPlayerInfo.GetPos(), &vecRestartPos, &fRestartFloat);
			CRestart::OverrideHospitalLevel = LEVEL_GENERIC;
			CRestart::OverridePoliceStationLevel = LEVEL_GENERIC;
			PassTime(720);
			RestorePlayerStuffDuringResurrection(pPlayerInfo.m_pPed, vecRestartPos, fRestartFloat);
			SortOutStreamingAndMemory(pPlayerInfo.GetPos());
			TheCamera.m_fCamShakeForce = 0.0f;
			TheCamera.SetMotionBlur(0, 0, 0, 0, MOTION_BLUR_NONE);
			CPad::GetPad(0)->StopShaking(0);
			CReferences::RemoveReferencesToPlayer();
			CCarCtrl::CountDownToCarsAtStart = 2;
			CPad::GetPad(CWorld::PlayerInFocus)->DisablePlayerControls = PLAYERCONTROL_ENABLED;
			if (CRestart::bFadeInAfterNextDeath) {
				TheCamera.SetFadeColour(200, 200, 200);
				TheCamera.Fade(4.0f, FADE_IN);
			} else CRestart::bFadeInAfterNextDeath = true;
		}
		break;
	case WBSTATE_BUSTED:
#ifdef MISSION_REPLAY
		if ((CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime > AddExtraDeathDelay() + 0x800) && (CTimer::GetPreviousTimeInMilliseconds() - pPlayerInfo.m_nWBTime <= AddExtraDeathDelay() + 0x800)) {
#else
		if ((CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime > 0x800) && (CTimer::GetPreviousTimeInMilliseconds() - pPlayerInfo.m_nWBTime <= 0x800)) {
#endif
			TheCamera.SetFadeColour(0, 0, 0);
			TheCamera.Fade(2.0f, FADE_OUT);
		}
#ifdef MISSION_REPLAY
		if (CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime >= AddExtraDeathDelay() + 0x1000) {
#else
		if (CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime >= 0x1000) {
#endif
			pPlayerInfo.m_WBState = WBSTATE_PLAYING;
			int takeMoney;

			switch (pPlayerInfo.m_pPed->m_pWanted->GetWantedLevel()) {
			case 0:
			case 1:
				takeMoney = 100;
				break;
			case 2:
				takeMoney = 200;
				break;
			case 3:
				takeMoney = 400;
				break;
			case 4:
				takeMoney = 600;
				break;
			case 5:
				takeMoney = 900;
				break;
			case 6:
				takeMoney = 1500;
				break;
			}
			if (pPlayerInfo.m_bGetOutOfJailFree) {
				pPlayerInfo.m_bGetOutOfJailFree = false;
			} else {
				pPlayerInfo.m_nMoney = Max(0, pPlayerInfo.m_nMoney - takeMoney);
				pPlayerInfo.m_pPed->ClearWeapons();
			}

			if (pPlayerInfo.m_pPed->bInVehicle) {
				CVehicle *pVehicle = pPlayerInfo.m_pPed->m_pMyVehicle;
				if (pVehicle != nil) {
					if (pVehicle->pDriver == pPlayerInfo.m_pPed) {
						pVehicle->pDriver = nil;
						if (pVehicle->GetStatus() != STATUS_WRECKED)
							pVehicle->SetStatus(STATUS_ABANDONED);
					}
					else
						pVehicle->RemovePassenger(pPlayerInfo.m_pPed);
				}
			}
			CEventList::Initialise();
#ifdef SCREEN_DROPLETS
			ScreenDroplets::Initialise();
#endif
			CMessages::ClearMessages();
			CCarCtrl::ClearInterestingVehicleList();
			CWorld::ClearExcitingStuffFromArea(pPlayerInfo.GetPos(), 4000.0f, 1);
			CRestart::FindClosestPoliceRestartPoint(pPlayerInfo.GetPos(), &vecRestartPos, &fRestartFloat);
			CRestart::OverrideHospitalLevel = LEVEL_GENERIC;
			CRestart::OverridePoliceStationLevel = LEVEL_GENERIC;
			PassTime(720);
			RestorePlayerStuffDuringResurrection(pPlayerInfo.m_pPed, vecRestartPos, fRestartFloat);
			pPlayerInfo.m_pPed->ClearWeapons();
			SortOutStreamingAndMemory(pPlayerInfo.GetPos());
			TheCamera.m_fCamShakeForce = 0.0f;
			TheCamera.SetMotionBlur(0, 0, 0, 0, MOTION_BLUR_NONE);
			CPad::GetPad(0)->StopShaking(0);
			CReferences::RemoveReferencesToPlayer();
			CCarCtrl::CountDownToCarsAtStart = 2;
			CPad::GetPad(CWorld::PlayerInFocus)->DisablePlayerControls = PLAYERCONTROL_ENABLED;
			if (CRestart::bFadeInAfterNextArrest) {
				TheCamera.SetFadeColour(0, 0, 0);
				TheCamera.Fade(4.0f, FADE_IN);
			} else CRestart::bFadeInAfterNextArrest = true;
		}
		break;
	case WBSTATE_FAILED_CRITICAL_MISSION:
#ifdef MISSION_REPLAY
		if ((CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime > AddExtraDeathDelay() + 0x800) && (CTimer::GetPreviousTimeInMilliseconds() - pPlayerInfo.m_nWBTime <= AddExtraDeathDelay() + 0x800)) {
#else
		if ((CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime > 0x800) && (CTimer::GetPreviousTimeInMilliseconds() - pPlayerInfo.m_nWBTime <= 0x800)) {
#endif
			TheCamera.SetFadeColour(0, 0, 0);
			TheCamera.Fade(2.0f, FADE_OUT);
		}
#ifdef MISSION_REPLAY
		if (CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime >= AddExtraDeathDelay() + 0x1000) {
#else
		if (CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime >= 0x1000) {
#endif
			pPlayerInfo.m_WBState = WBSTATE_PLAYING;
			if (pPlayerInfo.m_pPed->bInVehicle) {
				CVehicle *pVehicle = pPlayerInfo.m_pPed->m_pMyVehicle;
				if (pVehicle != nil) {
					if (pVehicle->pDriver == pPlayerInfo.m_pPed) {
						pVehicle->pDriver = nil;
						if (pVehicle->GetStatus() != STATUS_WRECKED)
							pVehicle->SetStatus(STATUS_ABANDONED);
					} else
						pVehicle->RemovePassenger(pPlayerInfo.m_pPed);
				}
			}
			CEventList::Initialise();
#ifdef SCREEN_DROPLETS
			ScreenDroplets::Initialise();
#endif
			CMessages::ClearMessages();
			CCarCtrl::ClearInterestingVehicleList();
			CWorld::ClearExcitingStuffFromArea(pPlayerInfo.GetPos(), 4000.0f, 1);
			CRestart::FindClosestPoliceRestartPoint(pPlayerInfo.GetPos(), &vecRestartPos, &fRestartFloat);
			CRestart::OverridePoliceStationLevel = LEVEL_GENERIC;
			CRestart::OverrideHospitalLevel = LEVEL_GENERIC;
			RestorePlayerStuffDuringResurrection(pPlayerInfo.m_pPed, vecRestartPos, fRestartFloat);
			SortOutStreamingAndMemory(pPlayerInfo.GetPos());
			TheCamera.m_fCamShakeForce = 0.0f;
			TheCamera.SetMotionBlur(0, 0, 0, 0, MOTION_BLUR_NONE);
			CPad::GetPad(0)->StopShaking(0);
			CReferences::RemoveReferencesToPlayer();
			CCarCtrl::CountDownToCarsAtStart = 2;
			CPad::GetPad(CWorld::PlayerInFocus)->DisablePlayerControls = PLAYERCONTROL_ENABLED;
			TheCamera.SetFadeColour(0, 0, 0);
			TheCamera.Fade(4.0f, FADE_IN);
		}
		break;
	case 4:
		return;
	}
}

void
CGameLogic::RestorePlayerStuffDuringResurrection(CPlayerPed *pPlayerPed, CVector pos, float angle)
{
	pPlayerPed->m_fHealth = 100.0f;
	pPlayerPed->m_fArmour = 0.0f;
	pPlayerPed->bIsVisible = true;
	pPlayerPed->m_bloodyFootprintCountOrDeathTime = 0;
	pPlayerPed->bDoBloodyFootprints = false;
	pPlayerPed->ClearAdrenaline();
	pPlayerPed->m_fCurrentStamina = pPlayerPed->m_fMaxStamina;
	if (pPlayerPed->m_pFire)
		pPlayerPed->m_pFire->Extinguish();
	pPlayerPed->bInVehicle = false;
	pPlayerPed->m_pMyVehicle = nil;
	pPlayerPed->m_pVehicleAnim = nil;
	pPlayerPed->m_pWanted->Reset();
	pPlayerPed->RestartNonPartialAnims();
	pPlayerPed->GetPlayerInfoForThisPlayerPed()->MakePlayerSafe(false);
	pPlayerPed->bRemoveFromWorld = false;
	pPlayerPed->ClearWeaponTarget();
	pPlayerPed->SetInitialState();
	CCarCtrl::ClearInterestingVehicleList();

	pos.z += 1.0f;
	pPlayerPed->Teleport(pos);
	pPlayerPed->SetMoveSpeed(CVector(0.0f, 0.0f, 0.0f));

	pPlayerPed->m_fRotationCur = DEGTORAD(angle);
	pPlayerPed->m_fRotationDest = pPlayerPed->m_fRotationCur;
	pPlayerPed->SetHeading(pPlayerPed->m_fRotationCur);
	CTheScripts::ClearSpaceForMissionEntity(pos, pPlayerPed);
	CWorld::ClearExcitingStuffFromArea(pos, 4000.0, 1);
	pPlayerPed->RestoreHeadingRate();
	TheCamera.SetCameraDirectlyInFrontForFollowPed_CamOnAString();
	CReferences::RemoveReferencesToPlayer();
	CGarages::PlayerArrestedOrDied();
	CStats::CheckPointReachedUnsuccessfully();
	CWorld::Remove(pPlayerPed);
	CWorld::Add(pPlayerPed);
}


code:
#pragma once

class CGameLogic
{
public:
	static void InitAtStartOfGame();
	static void PassTime(uint32 time);
	static void SortOutStreamingAndMemory(const CVector &pos);
	static void Update();
	static void RestorePlayerStuffDuringResurrection(class CPlayerPed *pPlayerPed, CVector pos, float angle);

	static uint8 ActivePlayers;
};