Files
GTASource/game/audio/scannermanager.h
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

460 lines
12 KiB
C++

//
// audio/policescanner.h
//
// Copyright (C) 1999-2007 Rockstar Games. All Rights Reserved.
//
#ifndef SCANNERMANAGER_H_INCLUDED
#define SCANNERMANAGER_H_INCLUDED
#include "audiodefines.h"
#if NA_POLICESCANNER_ENABLED
#include "gameobjects.h"
#include "game/crime.h"
#include "audioentity.h"
#include "atl/array.h"
#include "audiosoundtypes/soundcontrol.h"
#include "audiosoundtypes/speechsound.h"
#include "audiohardware/waveslot.h"
#include "bank/bkmgr.h"
#include "renderer/color.h"
class CPed;
class CEntity;
class audVehicleAudioEntity;
class naEnvironmentGroup;
class audScene;
#define AUD_NUM_CDI_VOICES (22)
const u32 g_MaxPhrasesPerSentence = 16;
const u32 g_MaxBufferedSentences = 32;
enum audScannerState
{
AUD_SCANNER_IDLE,
AUD_SCANNER_PREPARING,
AUD_SCANNER_PLAYBACK,
AUD_SCANNER_POSTDELAY,
AUD_SCANNER_HANDLING_COP_DISPATCH_INTERACTION,
};
enum audScannerSentenceType
{
AUD_SCANNER_CRIME_REPORT,
AUD_SCANNER_ASSISTANCE_REQUIRED,
AUD_SCANNER_SUSPECT_SPOTTED,
AUD_SCANNER_SINGLE_DISPATCH,
AUD_SCANNER_MULTI_DISPATCH,
AUD_SCANNER_SUSPECT_DOWN,
AUD_SCANNER_RANDOM_CHAT,
AUD_SCANNER_SCRIPTED,
AUD_SCANNER_TRAIN,
AUD_SCANNER_UNKNOWN,
};
enum audUnitType
{
AUD_UNIT_NORMAL,
AUD_UNIT_SWAT,
AUD_UNIT_AIR,
AUD_UNIT_FBI,
};
enum audDirection
{
AUD_DIR_NORTH,
AUD_DIR_EAST,
AUD_DIR_SOUTH,
AUD_DIR_WEST,
AUD_DIR_UNKNOWN,
};
enum audScannerPriority
{
AUD_SCANNER_PRIO_AMBIENT,
AUD_SCANNER_PRIO_LOW,
AUD_SCANNER_PRIO_NORMAL,
AUD_SCANNER_PRIO_HIGH,
AUD_SCANNER_PRIO_CRITICAL,
};
enum ScannerSlots
{
SCANNER_SLOT_NULL = -1,
SCANNER_SLOT_1 = 0,
SCANNER_SLOT_2,
SCANNER_SLOT_3,
SCANNER_SLOT_4,
SCANNER_SMALL_SLOT_1,
SCANNER_SMALL_SLOT_2,
SCANNER_SMALL_SLOT_3,
SCANNER_SMALL_SLOT_4,
NUM_SCANNERSLOTS,
SCANNERSLOTS_MAX = NUM_SCANNERSLOTS,
};
//enum ScannerCopDispatchInteractionClass
//{
// SCANNER_CDIC_NONE,
// SCANNER_CDIC_NORMAL,
// SCANNER_CDIC_COP_RESPONSE,
// SCANNER_CDIC_POSSIBLE_HELI_RESPONSE,
// SCANNER_CDIC_HELI,
//
// SCANNER_CDIC_TOT_NUM
//};
enum ScannerCopDispatchInteractionType
{
SCANNER_CDIT_NONE,
SCANNER_CDIT_REPORT_SUSPECT_CRASHED_VEHICLE,
SCANNER_CDIT_REPORT_SUSPECT_ENTERED_FREEWAY,
SCANNER_CDIT_REPORT_SUSPECT_ENTERED_METRO,
SCANNER_CDIT_REPORT_SUSPECT_IS_IN_CAR,
SCANNER_CDIT_REPORT_SUSPECT_IS_ON_FOOT,
SCANNER_CDIT_REPORT_SUSPECT_IS_ON_MOTORCYCLE,
SCANNER_CDIT_REPORT_SUSPECT_LEFT_FREEWAY,
SCANNER_CDIT_REQUEST_BACKUP,
SCANNER_CDIT_ACKNOWLEDGE_SITUATION_DISPATCH,
SCANNER_CDIT_UNIT_RESPONDING_DISPATCH,
SCANNER_CDIT_REQUEST_GUIDANCE_DISPATCH,
SCANNER_CDIT_HELI_MAYDAY_DISPATCH,
SCANNER_CDIT_SHOT_AT_HELI_MEGAPHONE,
SCANNER_CDIT_HELI_APPROACHING_DISPATCH,
SCANNER_CDIT_PLAYER_SPOTTED,
SCANNER_CDIT_TOT_NUM
};
struct audScannerPhrase
{
audMetadataRef soundMetaRef;
audSound *sound;
audSound *echoSound;
u32 postDelay;
ScannerSlots slot;
bool isPlayerHeading;
#if __BANK
char debugName[64];
#endif
};
struct audScannerVehicleHistory
{
audVehicleAudioEntity *audioEntity;
bool hasDescribedColour;
bool hasDescribedModel;
bool hasDescribedManufacturer;
bool hasDescribedCategory;
bool isOnFoot;
bool isPlayer;
};
struct audScannerSentence
{
Vector3 position;
audTracker *tracker;
f32 policeScannerApplyValue;
u32 timeRequested;
audScannerPriority priority;
audScannerSentenceType sentenceType;
u32 sentenceSubType;
audMetadataRef areaHash;
u32 currentPhrase;
u32 numPhrases;
atRangeArray<audScannerPhrase, g_MaxPhrasesPerSentence> phrases;
audEnvironmentGroupInterface *occlusionGroup;
audCategory *category;
u32 backgroundSFXHash;
u32 predelay;
u32 fakeEchoTime;
u32 voiceNum;
s32 scriptID;
eCrimeType crimeId;
ScannerSlots m_LastUsedScannerSlot;
ScannerSlots m_LastUsedSmallScannerSlot;
audScannerVehicleHistory vehicleHistory;
atRangeArray<bool, SCANNERSLOTS_MAX> m_SlotIsInUse;
bool isPositioned;
bool inUse;
bool gotAllSlots;
bool shouldDuckRadio;
bool useRadioVolOffset;
bool isPlayerCrime;
bool playAcknowledge;
bool playResponding;
#if __BANK
char debugName[64];
#endif
};
struct audVehicleDescription
{
audVehicleDescription() :
prefixSound(0),
colourSound(0),
manufacturerSound(0),
modelSound(0),
category(0),
audioEntity(NULL),
isInVehicle(false),
isVehicleKnown(false),
isMotorbike(false)
{};
u32 prefixSound;
u32 colourSound;
u32 manufacturerSound;
u32 modelSound;
u32 category;
audVehicleAudioEntity *audioEntity;
bool isInVehicle;
bool isVehicleKnown;
bool isMotorbike;
};
struct audPositionDescription
{
audMetadataRef areaSound;
audMetadataRef streetSound;
u32 inDirectionSound;
audMetadataRef areaConjunctiveSound;
audMetadataRef streetConjunctiveSound;
u32 locationSound;
u32 locationDirectionSound;
};
struct audPoliceSpotting
{
audPositionDescription posDescription;
audVehicleDescription vehDescription;
audScannerPriority priority;
audDirection heading;
f32 speed;
bool forceVehicle;
bool fromScript;
bool isPlayerHeading;
};
struct audCrimeReport
{
audCrimeReport()
{
duckRadio = false;
}
audPositionDescription posDescription;
audScannerPriority priority;
ScannerCrimeReport *crime;
u32 crimeId;
u32 delay;
u32 subtype;
bool duckRadio;
};
struct audWeightedVariation
{
u32 item;
f32 weight;
};
class CVehicle;
class audScannerManager : naAudioEntity
{
friend class audPoliceScanner;
friend class audTrainAudioEntity;
public:
AUDIO_ENTITY_NAME(audScannerManager);
audScannerManager();
virtual ~audScannerManager();
void Init();
void Shutdown();
void Update();
audScannerSentence *AllocateSentence(bool priorityCheck=false, audScannerPriority priorityToCheckAgainst=AUD_SCANNER_PRIO_AMBIENT, const u32 voiceNum=0);
void CancelAnyPlayingReportsNextFade();
void CancelAnyPlayingReports(const u32 ReleaseTime = 0);
void CancelAllReports();
void CancelAnySentencesFromTracker(audTracker *tracker);
void CancelAnySentencesFromEntity(audVehicleAudioEntity *entity);
void DisableScanner();
void EnableScanner();
void DisableScannerFlagChanged(const bool state);
s32 TriggerScriptedReport(const char *scriptedReportName,f32 applyValue = 0.f);
void PopulateSentenceWithPosDescription(const audPositionDescription &desc, audScannerSentence* sentence, u32 &idx);
void CancelScriptedReport(s32 scriptID);
bool IsScriptedReportPlaying(s32 scriptID);
bool IsScriptedReportValid(s32 scriptID);
s32 GetPlayingScriptedReport();
f32 GetPoliceScannerApplyValue() {return m_RequestedSentences[m_PlayingSentenceIndex].policeScannerApplyValue;}
void SetCarUnitValues(s32 UnitTypeNum, s32 BeatNum);
void SetPositionValue(const Vector3 &pos);
void SetCrimeValue(s32 crime);
void ReportResistArrest(const Vector3& pos, u32 delay);
void ResetResistArrest();
bool HasCrimeBeenReportedRecently(const eCrimeType crime, u32 timeInMs);
bool ShouldDuckRadio() const
{
return (m_ScannerState == AUD_SCANNER_PLAYBACK && m_RequestedSentences[m_PlayingSentenceIndex].shouldDuckRadio);
}
inline audMetadataRef GetLastSpokenAreaHash() {return m_LastSpokenAreaHash;}
inline audDirection GetPlayerHeading() {return m_PlayerHeading;}
void SetTimeToPlayCDIVehicleLine();
void TriggerCopDispatchInteraction(ScannerCopDispatchInteractionType interaction);
bool ReallyTriggerCopDispatchInteraction(ScannerCopDispatchInteractionType interaction);
void SetPlayerSpottedTime(CPed* pSpotter);
void SetShouldChooseNewHeliVoice() { m_ShouldChooseNewHeliVoice = true; }
void SetShouldChooseNewNonHeliVoice() { m_ShouldChooseNewNonHeliVoice = true; }
void IncrementCopShot() { m_CopShotTally++; }
bool ShouldTryToPlayShotAtHeli(u32 audioTime) { return audioTime >= m_TimeCDIsCanPlay[SCANNER_CDIT_SHOT_AT_HELI_MEGAPHONE]; }
void IncrementHelisInChase();
void DecrementHelisInChase();
void StartScannerNoise(bool isDispatch = false, s32 predelay = -1);
void StopScannerNoise();
bool CanPlayRefuellingReport();
u32 GetLastTimePlayerWasClean() { return m_LastTimePlayerWasClean; }
void SetTimeCheckedLastPosition(u32 time) { m_TimeLastCheckedPosition = time; }
static audDirection CalculateAudioDirection(const Vector3 &vDirection);
#if __BANK
void AddWidgets(bkBank &bank);
#endif
private:
bool ChooseSentenceToPlay(u32 &sentenceIndex);
audPrepareState PrepareSentence(const u32 sentenceIndex);
bool CreateSentenceSounds(const u32 sentenceIndex);
void CleanupSentenceSounds(const u32 sentenceIndex, const u32 ReleaseTime = 0);
void UpdateHistory();
bool IsSentenceStillValid(const u32 index);
void InitSentenceForScanner(const u32 index, const u32 voiceNum = 0);
u32 GetScannerHashForVoice(const char* input, const u32& voiceNum);
u32 GetScannerHashForVoice(const u32& input, const u32& voiceNum);
u32 SelectScannerVoice();
ScannerSlots GetNextSmallScannerSlot(audScannerSentence& sentence);
ScannerSlots GetNextScannerSlot(audScannerSentence& sentence);
void DecrementNextSmallScannerSlot(audScannerSentence& sentence);
void DecrementNextScannerSlot(audScannerSentence& sentence);
//Scripted procedural resolving functions
void SelectCarUnitSounds(u32& compositeCodeSound, u32& unitTypeSound, u32& beatSound, u32 voiceNum);
void ResetScriptSetVariables();
void HandleCopDispatchInteraction();
void TriggerCopDispatchInteractionVehicleLine();
void FinishCopDispatchInteraction();
void CancelCopDispatchInteraction();
u32 GetVoiceHashForCopSpeech();
u32 GetVoiceHashForCopSpottedSpeech();
u32 GetVoiceHashForHeliCopSpeech();
bool PlayCopToDispatchLine();
void PlayDispatchAcknowledgementLine();
void PlayHeliGuidanceLine(u32 currentTime);
u32 GetNextPlayTimeForCDI(ScannerCopDispatchInteractionType m_DispatchInteractionType, u32 currentTime);
bool CanDoCopSpottingLine();
Vector3 m_LastPlayerPosition;
u32 m_TimeLastCheckedPosition;
Vector3 m_ScriptSetPos;
eCrimeType m_ScriptSetCrime;
u32 m_StateChangeTimeMs;
u32 m_LastReportTimeMs;
u32 m_CurrentSentenceIndex;
u32 m_PlayingSentenceIndex;
audScannerSentenceType m_LastSentenceType;
u32 m_LastSentenceSubType;
audMetadataRef m_LastSpokenAreaHash;
u32 m_NextRandomChatTime;
u32 m_ValidSentenceTypes;
audScannerState m_ScannerState;
audDirection m_PlayerHeading;
u32 m_LastScriptedLineTimeMs;
//To allow script to check if a given triggered-line is queued, playing, etc.
u32 m_NextScriptedLineID;
s32 m_UnitTypeNumber;
s32 m_BeatNumber;
u32 m_TimeResistArrestLastTriggered;
Vector3 m_PosForDelayedResistArrest;
u32 m_DelayForDelayedResistArrest;
audSound *m_NoiseLoop;
audScene* m_ScannerMixScene;
atArray<audWaveSlot*> m_ScannerSlots;
atRangeArray<audScannerSentence, g_MaxBufferedSentences> m_RequestedSentences;
atRangeArray<u32, SCANNER_CDIT_TOT_NUM> m_DispIntCopSpeechContextPHash;
audSpeechSound* m_DispIntCopSpeechSound;
u32 m_DispatchInteractionCopVoicehash;
u32 m_DispatchInteractionHeliCopVoicehash;
u32 m_TimeAnyCDICanPlay;
u32 m_TimeToPlayDispIntLine;
u32 m_TimeToPlayDispIntResponse;
u32 m_MinTimeForNextCDIVehicleLine;
u32 m_MaxTimeForNextCDIVehicleLine;
u32 m_LastTimeSeenByHeliCop;
u32 m_LastTimeSeenByNonHeliCop;
u32 m_TimeLastCDIFinished;
u32 m_LastTimePlayerWasClean;
atRangeArray<u32, SCANNER_CDIT_TOT_NUM> m_TimeCDIsCanPlay;
u8 m_CopShotTally;
s8 m_HelisInvolvedInChase;
ScannerCopDispatchInteractionType m_DispatchInteractionType;
ScannerCopDispatchInteractionType m_DispatchInteractionTypeTriggered;
bool m_DispIntCopHasSpoken;
bool m_DispInDispHasSpoken;
bool m_WaitingOnDispIntResponse;
bool m_ForceDispIntResponseThrough;
bool m_DispIntHeliHasSpoken;
bool m_DispIntHeliMegaphoneHasSpoken;
bool m_DispIntHeliMegaphoneShouldSpeak;
bool m_ShouldChooseNewHeliVoice;
bool m_ShouldChooseNewNonHeliVoice;
bool m_LastHeliGuidanceLineWasNoVisual;
bool m_AmbientScannerEnabled;
bool m_WantToCancelReport;
bool m_DelayingReportCancellationUntilLineEnd;
bool m_HasTriggerGuidanceDispatch;
};
#endif // NA_POLICESCANNER_ENABLED
#endif // SCANNERMANAGER_H_INCLUDED