Files
GTASource/game/event/ShockingEvents.cpp
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

999 lines
31 KiB
C++

#include "event/ShockingEvents.h"
#include "event/EventGroup.h"
#include "event/EventShocking.h"
#include "debug/VectorMap.h"
#include "Peds/ped.h"
#include "profile/profiler.h"
#include "scene/world/GameWorld.h"
// TODO: clean these up
PF_PAGE(GTAShockingEvents, "GTA ShockingEvents");
PF_GROUP(ShockingEvents);
PF_LINK(GTAShockingEvents, ShockingEvents);
PF_TIMER(Add_Total, ShockingEvents);
PF_TIMER(Add_EventAlreadyExists, ShockingEvents);
PF_TIMER(Add_GlobalGroupAdd, ShockingEvents);
AI_OPTIMISATIONS()
//-----------------------------------------------------------------------------
#if __BANK
bool CShockingEventsManager::RENDER_VECTOR_MAP = false;
bool CShockingEventsManager::RENDER_AS_LIST = false;
bool CShockingEventsManager::RENDER_ON_3D_SCREEN = false;
bool CShockingEventsManager::RENDER_EVENT_EFFECT_AREA = false;
bool CShockingEventsManager::RENDER_SHOCK_EVENT_LEVEL_INTERESTING = true;
bool CShockingEventsManager::RENDER_SHOCK_EVENT_LEVEL_AFFECTSOTHERS = true;
bool CShockingEventsManager::RENDER_SHOCK_EVENT_LEVEL_POTENTIALLYDANGEROUS = true;
bool CShockingEventsManager::RENDER_SHOCK_EVENT_LEVEL_SERIOUSDANGER = true;
#endif
bool CShockingEventsManager::ms_bDisableEvents = false;
fwFlags8 CShockingEventsManager::ms_SuppressedShockingEventPriorities;
u32 CShockingEventsManager::Add(CEventShocking &ev, bool createdByScript, float overrideLifeTime)
{
PF_FUNC(Add_Total);
if(ms_bDisableEvents)
{
return 0;
}
if (IsShockingEventSuppressed(ev))
{
return 0;
}
#if 0
if(eType == ESeenMeleeAction
|| eType == ESeenGangFight
|| eType == EGunFight
|| eType == EExplosion
|| eType == EFire
|| eType == EGunshotFired)
{
//dont have to have an Entity
}
else
{
//*MUST* have a pEntity
Assert(ev.m_pEntitySource);
}
#endif
// TODO: Reimplement the visible weapon stuff somehow.
#if 0
//special conversion for visible weapons - I *love* special cases.....
if(eType == EVisibleWeapon)
eType = (eSEventTypes)ConvertVisibleWeaponEType(nWeaponHash);
ev.m_eType = eType;
#endif
const CEventShocking::Tunables &tunables = ev.GetTunables();
//vars to record which event is closest to completing in case ShockLevel is full
u32 nCurrentTime = fwTimer::GetTimeInMilliseconds();
ev.m_iStartTime = nCurrentTime;
ev.SetCreatedByScript(createdByScript);
float lifeTime = tunables.m_LifeTime;
if(overrideLifeTime >= 0.0f)
{
lifeTime = overrideLifeTime;
}
ev.m_iLifeTime = (int)(1000.0f*lifeTime);
// If the event is script-created, only allow a lifetime of 0 (which is interpreted
// as infinite) if passed in as an override. Events that happen to have the lifetime
// set to 0 in their tuning data will just live for a short amount of time. Script-created
// events with lifetime 0 are a bit risky in case they forget to remove them, but
// should be OK as at least we tend to clear out all events on death etc.
if(createdByScript && overrideLifeTime != 0.0f)
{
ev.m_iLifeTime = Max(ev.m_iLifeTime, 1U);
}
ev.m_fEventRadius += tunables.m_VisualReactionRange;
// Set the priority of the event. It would be better if the parser knew about
// eEventPriorityList so CEventShocking::Tunables could simply contain an enum
// value of that type and eSEventShockLevels could go away, but that would be a bit
// of a bigger change than I want to make right now.
eEventPriorityList pri = E_PRIORITY_SHOCKING_EVENT_INTERESTING;
switch(tunables.m_Priority)
{
case EInteresting:
pri = E_PRIORITY_SHOCKING_EVENT_INTERESTING;
break;
case EAffectsOthers:
pri = E_PRIORITY_SHOCKING_EVENT_AFFECTS_OTHERS;
break;
case EPotentiallyDangerous:
pri = E_PRIORITY_SHOCKING_EVENT_POTENTIALLY_DANGEROUS;
break;
case EDangerous:
pri = E_PRIORITY_SHOCKING_EVENT_DANGEROUS;
break;
case ESeriousDanger:
pri = E_PRIORITY_SHOCKING_EVENT_SERIOUS_DANGER;
break;
default:
Assertf(0, "Invalid shocking event priority %d.", tunables.m_Priority);
break;
}
ev.m_Priority = pri;
//check event does not already exist, if it does, the sub function updates with necessary changes then quit
PF_START(Add_EventAlreadyExists);
// Don't check if the event already exists if script wants to add the event.
if(!createdByScript && EventAlreadyExists(ev))
{
PF_STOP(Add_EventAlreadyExists);
return 0;
}
PF_STOP(Add_EventAlreadyExists);
PF_START(Add_GlobalGroupAdd);
u32 id = ev.GetId();
if(!GetEventGlobalGroup()->Add(ev))
{
PF_STOP(Add_GlobalGroupAdd);
// Failed to add it, not sure if we should print a warning or something here.
return 0;
}
PF_STOP(Add_GlobalGroupAdd);
return id;
}
//clears all existing events
void CShockingEventsManager::ClearAllEvents(bool clearNonScriptCreated, bool clearScriptCreated)
{
CEventGroupGlobal& global = *GetEventGlobalGroup();
AI_EVENT_GROUP_LOCK(&global)
int num = global.GetNumEvents();
for(int j = 0; j < num; j++)
{
fwEvent* ev = global.GetEventByIndex(j);
if(!ev || !static_cast<const CEvent*>(ev)->IsShockingEvent())
{
continue;
}
const CEventShocking& shocking = *static_cast<const CEventShocking*>(ev);
const bool createdByScript = shocking.GetCreatedByScript();
if((createdByScript && !clearScriptCreated) || (!createdByScript && !clearNonScriptCreated))
{
continue;
}
global.Remove(*ev);
j--;
num--;
}
}
void CShockingEventsManager::ClearEventsInSphere(Vec3V_In sphereCenter, const float& sphereRadius, bool clearNonScriptCreated, bool clearScriptCreated)
{
const Vec3V sphereCenterV = sphereCenter;
const ScalarV sphereRadiusV = LoadScalar32IntoScalarV(sphereRadius);
const ScalarV sphereRadiusSqV = Scale(sphereRadiusV, sphereRadiusV);
CEventGroupGlobal& global = *GetEventGlobalGroup();
AI_EVENT_GROUP_LOCK(&global)
int num = global.GetNumEvents();
for(int j = 0; j < num; j++)
{
fwEvent* ev = global.GetEventByIndex(j);
if(!ev || !static_cast<const CEvent*>(ev)->IsShockingEvent())
{
continue;
}
const CEventShocking& shocking = *static_cast<const CEventShocking*>(ev);
const bool createdByScript = shocking.GetCreatedByScript();
if((createdByScript && !clearScriptCreated) || (!createdByScript && !clearNonScriptCreated))
{
continue;
}
const Vec3V eventPosV = shocking.GetEntityOrSourcePosition();
const ScalarV distSqV = DistSquared(sphereCenterV, eventPosV);
if(IsGreaterThanAll(distSqV, sphereRadiusSqV))
{
continue;
}
global.Remove(*ev);
j--;
num--;
}
}
//clears all existing events that have the entity as the source
void CShockingEventsManager::ClearAllEventsWithSourceEntity(const CEntity* pSourceEntity)
{
CEventGroupGlobal& global = *GetEventGlobalGroup();
AI_EVENT_GROUP_LOCK(&global)
int num = global.GetNumEvents();
for(int j = 0; j < num; j++)
{
fwEvent* ev = global.GetEventByIndex(j);
if(!ev || !static_cast<const CEvent*>(ev)->IsShockingEvent())
{
continue;
}
CEntity* pEventSourceEntity = static_cast<const CEventShocking*>(ev)->GetSourceEntity();
if( pEventSourceEntity != pSourceEntity)
{
bool bPedDrivingSourceVeh = false;
if (pSourceEntity && pSourceEntity->GetIsTypePed())
{
const CPed* pSrcPed = static_cast<const CPed*>(pSourceEntity);
if (pSrcPed->GetIsDrivingVehicle())
{
CVehicle* pSrcVeh = pSrcPed->GetVehiclePedInside();
if (pSrcVeh->GetDriver() == pSrcPed && pSrcVeh == pEventSourceEntity)
{
bPedDrivingSourceVeh = true;
}
}
}
if (!bPedDrivingSourceVeh)
continue;
}
global.Remove(*ev);
j--;
num--;
}
}
void CShockingEventsManager::ClearAllBlockingAreas()
{
// First, just clear out any references we have to the blocking areas.
// We don't want to risk messing with somebody else's reuse of the blocking areas.
// Note: this already seems a bit fragile in other parts of this code: we seem to basically
// be relying on the delay to be longer than the period of ApplySpecialBehaviors() calls...
CEventGroupGlobal& global = *GetEventGlobalGroup();
AI_EVENT_GROUP_LOCK(&global)
int num = global.GetNumEvents();
for(int j = 0; j < num; j++)
{
fwEvent* ev = global.GetEventByIndex(j);
if(!ev || !static_cast<const CEvent*>(ev)->IsShockingEvent())
{
continue;
}
CEventShocking* pShockingEvent = static_cast<CEventShocking*>(ev);
pShockingEvent->m_iPedGenBlockingAreaIndex = -1;
}
// Clear all blocking areas for shocking events.
// Note that we couldn't just have used the m_iPedGenBlockingAreaIndex values
// from the events, because we intentionally let the blocking areas live longer
// than the events.
CPathServer::GetAmbientPedGen().ClearAllPedGenBlockingAreasWithSpecificOwner(CPedGenBlockedArea::EShockingEvent);
}
bool CShockingEventsManager::EventAlreadyExists(CEventShocking& event)
{
const int eType = event.GetEventType();
const Vector3 &vEventPosition1 = RCC_VECTOR3(event.m_vEventPosition);
CEntity* pEntityA = event.m_pEntitySource;
CEntity* pEntityB = event.m_pEntityOther;
// Would be nice to not have to do this, but since we seem to be getting these sometimes,
// it's probably worth it for the increased stability, assuming that we still try to track
// down the root of the problem.
if(!Verifyf(vEventPosition1.FiniteElements(),
"Invalid numbers in shocking event position (%f, %f, %f), please track down where they came from.",
vEventPosition1.x, vEventPosition1.y, vEventPosition1.z))
{
// This should prevent events with bad numbers from making it further into the system.
return true;
}
CEventGroupGlobal& global = *GetEventGlobalGroup();
AI_EVENT_GROUP_LOCK(&global)
const int num = global.GetNumEvents();
CEventShocking* pEvent = NULL;
for(int j = 0; j < num; j++)
{
fwEvent* ev = global.GetEventByIndex(j);
if(!ev || !static_cast<const CEvent*>(ev)->IsShockingEvent())
{
continue;
}
pEvent = static_cast<CEventShocking*>(ev);
if (!pEvent->GetCanBeMerged())
{
continue;
}
bool bTypeMatch = false;
if(pEvent->GetEventType() == event.GetEventType())
bTypeMatch = true;
/*if(eType >= EVisibleWeapon && eType <= EVisibleWeaponHEAVY )
{
if(pEvent->m_eType >= EVisibleWeapon && pEvent->m_eType <= EVisibleWeaponHEAVY )
bTypeMatch = true;
}
else*/ if(event.GetEventType() == EVENT_SHOCKING_GUNSHOT_FIRED && pEvent->GetEventType() == EVENT_SHOCKING_GUN_FIGHT)
bTypeMatch = true;
else if(event.GetEventType() == EVENT_SHOCKING_CAR_CRASH && pEvent->GetEventType() == EVENT_SHOCKING_CAR_PILE_UP)
bTypeMatch = true;
else if(event.GetEventType() == EVENT_SHOCKING_SEEN_MELEE_ACTION && pEvent->GetEventType() == EVENT_SHOCKING_SEEN_GANG_FIGHT)
bTypeMatch = true;
else if(event.GetEventType() == EVENT_SHOCKING_RUNNING_PED && pEvent->GetEventType() == EVENT_SHOCKING_RUNNING_STAMPEDE)
bTypeMatch = true;
u32 nLifeTime = event.m_iLifeTime;
// Never match with script created events. Script is expecting them to persist and not be merged / etc.
if (pEvent->GetCreatedByScript())
{
bTypeMatch = false;
}
if(bTypeMatch)
{
bool bMatch = false;
if(eType == EVENT_SHOCKING_EXPLOSION || eType == EVENT_SHOCKING_FIRE)
{
//if another explosion occurs near a current one, we merge them into a super explosion
float fDistanceSqr = (RCC_VECTOR3(pEvent->m_vEventPosition) - vEventPosition1).XYMag2();
if(( !pEntityA && !pEvent->m_pEntitySource && fDistanceSqr <= rage::square(10.0f)) ||
(pEntityA && pEntityA==pEvent->m_pEntitySource))
{
//update the event with the new details - keep the longest lifetime
pEvent->UpdateLifeTime(event.m_iLifeTime, fwTimer::GetTimeInMilliseconds());
//re-position halfway between the 2 explosions
Vector3 vecNewPos = RCC_VECTOR3(pEvent->m_vEventPosition) + vEventPosition1;
vecNewPos.Scale(0.5f);
Assert(pEvent->GetEventType() == event.GetEventType());
pEvent->m_vEventPosition = VECTOR3_TO_VEC3V(vecNewPos);
if(fDistanceSqr > rage::square(pEvent->m_fEventRadius))
pEvent->m_fEventRadius = rage::Sqrtf(fDistanceSqr);
//m_Events[i].m_uiEventID = GetNextIDnumber();
pEvent->m_bHasReactPosition = true;
pEvent->m_vReactPosition = event.m_vEventPosition;
pEvent->ApplySpecialBehaviors();
return true;
}
}
else if(eType == EVENT_SHOCKING_GUNSHOT_FIRED)
{
//if another gunshot occurs near a current one, we merge them into a gun fight
// of course, we also need to check for a gun fight.....
float fDistanceSqr = (RCC_VECTOR3(pEvent->m_vEventPosition) - vEventPosition1).XYMag2();
if(fDistanceSqr < 400.0f || fDistanceSqr < rage::square(pEvent->m_fEventRadius))
{
// count how many times this event has been supplemented
pEvent->m_nCountAdds++;
//re-position event position based on the influence of previous shots
float fNewInfluence = 1.0f / (float)(pEvent->m_nCountAdds + 1);
Vector3 vecNewPos = fNewInfluence * Vector3(vEventPosition1) + (1.0f - fNewInfluence)*RCC_VECTOR3(pEvent->m_vEventPosition);
//Vector3 vecDeltaPos = vecNewPos - pEvent->m_vEventPosition;
pEvent->m_vEventPosition = VECTOR3_TO_VEC3V(vecNewPos);
if(pEvent->m_nCountAdds > 10)
{
pEvent->SetUseSourcePosition(true);
nLifeTime = Max(nLifeTime, (u32)(1000.0f*CEventShockingGunFight::StaticGetTunables().m_LifeTime));
Assert(pEvent->GetEventType() == EVENT_SHOCKING_GUNSHOT_FIRED || pEvent->GetEventType() == EVENT_SHOCKING_GUN_FIGHT);
if(pEvent->GetEventType() == EVENT_SHOCKING_GUNSHOT_FIRED)
{
pEvent->m_fEventRadius += 10.0f;
// switch Id when it becomes a new type of event
//pEvent->m_uiEventID = GetNextIDnumber();
//pEvent->m_eType = EGunFight;
// Note: the old CShockingEventsManager used to change one event
// into another here, but now we remove the old event and create a
// new one instead. This may not be strictly necessary, but probably
// safest in case we have different subclasses and stuff, and may also
// help to ensure that the peds reconsider the new event.
CEventShockingGunFight newEvent;
pEvent->InitClone(newEvent, false); // Probably best to generate new ID.
Assert(newEvent.GetEventType() == EVENT_SHOCKING_GUN_FIGHT);
global.Remove(*pEvent);
pEvent = static_cast<CEventShocking*>(global.Add(newEvent));
}
}
//update the event with the new details
pEvent->UpdateLifeTime(nLifeTime, fwTimer::GetTimeInMilliseconds());
pEvent->ApplySpecialBehaviors();
return true;
}
}
else if(eType == EVENT_SHOCKING_CAR_CRASH)
{
//if another car crash occurs near a current one, we merge them into a car pile up
float fDistanceSqr = (RCC_VECTOR3(pEvent->m_vEventPosition) - vEventPosition1).XYMag2();
if(fDistanceSqr < 100.0f || fDistanceSqr < rage::square(pEvent->m_fEventRadius))
{
// count how many times this event has been supplemented
pEvent->m_nCountAdds++;
//re-position event position based on the influence of previous shots
float fNewInfluence = 1.0f / (float)(pEvent->m_nCountAdds + 1);
Vector3 vecNewPos = fNewInfluence * Vector3(vEventPosition1) + (1.0f - fNewInfluence)*RCC_VECTOR3(pEvent->m_vEventPosition);
//Vector3 vecDeltaPos = vecNewPos - pEvent->m_vEventPosition;
pEvent->m_vEventPosition = VECTOR3_TO_VEC3V(vecNewPos);
if(pEvent->m_nCountAdds > 3 && pEntityA != pEvent->m_pEntitySource && pEntityA != pEvent->m_pEntitySource)
{
Assert(pEvent->GetEventType() == EVENT_SHOCKING_CAR_CRASH || pEvent->GetEventType() == EVENT_SHOCKING_CAR_PILE_UP);
if(pEvent->GetEventType() == EVENT_SHOCKING_CAR_CRASH)
{
pEvent->m_fEventRadius += 10.0f;
//pEvent->m_uiEventID = GetNextIDnumber();
//pEvent->m_eType = ECarPileUp;
CEventShockingCarPileUp newEvent;
pEvent->InitClone(newEvent, false); // Probably best to generate new ID.
Assert(newEvent.GetEventType() == EVENT_SHOCKING_CAR_PILE_UP);
global.Remove(*pEvent);
pEvent = static_cast<CEventShocking*>(global.Add(newEvent));
}
}
if(fDistanceSqr > rage::square(pEvent->m_fEventRadius))
{
pEvent->m_fEventRadius = rage::Sqrtf(fDistanceSqr);
}
//update the event with the new details
pEvent->UpdateLifeTime(nLifeTime, fwTimer::GetTimeInMilliseconds());
pEvent->ApplySpecialBehaviors();
return true;
}
}
else if(eType == EVENT_SHOCKING_SEEN_MELEE_ACTION)
{
//if another fight occurs near a current one, we merge them into a gang fight
float fDistanceSqr = (RCC_VECTOR3(pEvent->m_vEventPosition) - vEventPosition1).XYMag2();
if(fDistanceSqr <= 100.0f || fDistanceSqr < rage::square(pEvent->m_fEventRadius))
{
//re-position event position based on the influence of previous shots
float fNewInfluence = 1.0f / (float)(pEvent->m_nCountAdds + 1);
Vector3 vecNewPos = fNewInfluence * Vector3(vEventPosition1) + (1.0f - fNewInfluence)*RCC_VECTOR3(pEvent->m_vEventPosition);
//Vector3 vecDeltaPos = vecNewPos - pEvent->m_vEventPosition;
pEvent->m_vEventPosition = VECTOR3_TO_VEC3V(vecNewPos);
if(pEvent->m_nCountAdds > 10 && pEntityA != pEvent->m_pEntitySource && pEntityA != pEvent->m_pEntitySource)
{
Assert(pEvent->GetEventType() == EVENT_SHOCKING_SEEN_MELEE_ACTION || pEvent->GetEventType() == EVENT_SHOCKING_SEEN_GANG_FIGHT);
if(pEvent->GetEventType() == EVENT_SHOCKING_SEEN_MELEE_ACTION)
{
pEvent->m_fEventRadius += 5.0f;
//pEvent->m_uiEventID = GetNextIDnumber();
//pEvent->m_eType = ESeenGangFight;
CEventShockingSeenGangFight newEvent;
pEvent->InitClone(newEvent, false); // Probably best to generate new ID.
Assert(newEvent.GetEventType() == EVENT_SHOCKING_SEEN_GANG_FIGHT);
global.Remove(*pEvent);
pEvent = static_cast<CEventShocking*>(global.Add(newEvent));
}
}
if(pEvent->m_pEntitySource && pEntityA != pEvent->m_pEntitySource)
{
// event is not attached to any one entity any more
pEvent->RemoveEntities();
//pEvent->m_uiEventID = GetNextIDnumber();
}
if(fDistanceSqr > rage::square(pEvent->m_fEventRadius))
pEvent->m_fEventRadius = rage::Sqrtf(fDistanceSqr);
//update the event with the new details
pEvent->UpdateLifeTime(nLifeTime, fwTimer::GetTimeInMilliseconds());
pEvent->ApplySpecialBehaviors();
return true;
}
}
else if(eType == EVENT_SHOCKING_RUNNING_PED)
{
//If multiple peds are running next to each other, merge them into a stampede.
float fDistanceSqr = (RCC_VECTOR3(pEvent->m_vEventPosition) - vEventPosition1).XYMag2();
// Always keep player running events unique
const bool bOneContainsThePlayer = pEntityA == CGameWorld::FindLocalPlayer() || pEvent->m_pEntitySource == CGameWorld::FindLocalPlayer();
if( pEntityA == pEvent->m_pEntitySource || ((fDistanceSqr < 225.0f || fDistanceSqr < rage::square(pEvent->m_fEventRadius)) && !bOneContainsThePlayer ) )
{
//Check if we have updated the event.
bool bUpdatedEvent = false;
//Check if the event is a running ped.
Assert(pEvent->GetEventType() == EVENT_SHOCKING_RUNNING_PED || pEvent->GetEventType() == EVENT_SHOCKING_RUNNING_STAMPEDE);
if(pEvent->GetEventType() == EVENT_SHOCKING_RUNNING_PED)
{
//Check if the source is different.
if(pEntityA != pEvent->m_pEntitySource)
{
//Update the event position.
pEvent->m_vEventPosition = Average(pEvent->m_vEventPosition, VECTOR3_TO_VEC3V(vEventPosition1));
pEvent->SetUseSourcePosition(true);
//Increase the radius.
pEvent->m_fEventRadius += 10.0f;
//Create a stampede event.
CEventShockingRunningStampede newEvent;
pEvent->InitClone(newEvent, false); // Probably best to generate new ID.
Assert(newEvent.GetEventType() == EVENT_SHOCKING_RUNNING_STAMPEDE);
//Add the stampede event.
global.Remove(*pEvent);
pEvent = static_cast<CEventShocking*>(global.Add(newEvent));
//Note that we updated the event.
bUpdatedEvent = true;
}
else
{
//Note that our event matches.
bMatch = true;
}
}
//The event is a stampede.
else
{
//Merge with the stampede.
pEvent->m_nCountAdds++;
//Calculate the new position.
float fNewInfluence = 1.0f / (float)(pEvent->m_nCountAdds);
Vector3 vecNewPos = fNewInfluence * Vector3(vEventPosition1) + (1.0f - fNewInfluence)*RCC_VECTOR3(pEvent->m_vEventPosition);
pEvent->m_vEventPosition = VECTOR3_TO_VEC3V(vecNewPos);
pEvent->SetUseSourcePosition(true);
//Note that we updated the event.
bUpdatedEvent = true;
}
//Check if we updated the event.
if(bUpdatedEvent)
{
//Update the event with the new details.
pEvent->UpdateLifeTime(nLifeTime, fwTimer::GetTimeInMilliseconds());
pEvent->ApplySpecialBehaviors();
return true;
}
}
}
else if (eType == EVENT_SHOCKING_BROKEN_GLASS)
{
// Merge IFF the smasher is the same and the two locations are close.
if (pEntityA == pEvent->m_pEntitySource)
{
if (IsLessThanAll(DistSquared(pEvent->m_vEventPosition, VECTOR3_TO_VEC3V(vEventPosition1)), ScalarV(10.0f * 10.0f)))
{
bMatch = true;
}
}
}
else
{
//for certain events, i.e. fighting, we don't want an event for each punch
if(pEntityA == pEvent->m_pEntitySource)
bMatch = true;
if(pEntityA == pEvent->m_pEntityOther)
bMatch = true;
if(pEntityB && pEntityB == pEvent->m_pEntitySource)
bMatch = true;
if(pEntityB && pEntityB == pEvent->m_pEntityOther)
bMatch = true;
}
if(bMatch)
{
//update the event with the new details
pEvent->UpdateLifeTime(nLifeTime, fwTimer::GetTimeInMilliseconds());
//if the event is a visible weapon, has the ped changed it to a "heavier" weapon?
// TODO: work out the visible weapon issues
#if 0
if(pEvent->m_eType >= EVisibleWeapon && pEvent->m_eType <= EVisibleWeaponHEAVY)
{
//if so, record the new weapon and give event new ID number, to ensure new reactions
if(eType > pEvent->m_eType)
{
pEvent->m_eType = eType;
pEvent->m_uiEventID = GetNextIDnumber();
}
}
#endif
return true;
}
}
}
return false;
}
#if __BANK
void CShockingEventsManager::RenderShockingEvents()
{
CEventGroupGlobal* list = GetEventGlobalGroup();
AI_EVENT_GROUP_LOCK(list)
const int num = list->GetNumEvents();
if( !RENDER_VECTOR_MAP && !RENDER_AS_LIST && !RENDER_ON_3D_SCREEN)
{
return;
}
char debugText[100];
int iNoOfTexts=0;
static Vector3 ScreenCoors(0.1f, 0.2f, 0.0f);
Vector2 vTextRenderScale(0.3f, 0.3f);
Vector2 vTextRenderPos(ScreenCoors.x, ScreenCoors.y);
float fVertDist = 0.025f;
if( RENDER_AS_LIST )
{
grcDebugDraw::Text(vTextRenderPos, Color_white, "Shocking events:");
iNoOfTexts++;
#if 0
sprintf( debugText, "Num Current Events: %d; Peds: %d", ms_uiNumActiveEvents, ms_uiPedsChecked );
vTextRenderPos.y = ScreenCoors.y + (iNoOfTexts++)*fVertDist;
grcDebugDraw::Text(vTextRenderPos, Color_white, debugText);
sprintf( debugText, "[1 Frame Max's] Events: %d; Peds: %d", ms_uiMaxEventsAdded, ms_uiMaxPedsChecked );
vTextRenderPos.y = ScreenCoors.y + (iNoOfTexts++)*fVertDist;
grcDebugDraw::Text(vTextRenderPos, Color_white, debugText);
#endif
}
if(RENDER_VECTOR_MAP)
{
CVectorMap::DrawCircle(Vector3(0.0f, 0.0f, 0.0f), 0.5f, Color_white, false);
}
int nEventsFound = 0;
for(int i=0; i<num; i++ )
{
fwEvent* ev = list->GetEventByIndex(i);
if(!ev || !static_cast<const CEvent*>(ev)->IsShockingEvent())
{
continue;
}
CEventShocking& shocking = *static_cast<CEventShocking*>(ev);
CEventShocking* pEvent = &shocking;
eEventType nEventType = (eEventType)pEvent->GetEventType();
const CEventShocking::Tunables& tunables = pEvent->GetTunables();
nEventsFound++;
float visualReactionRange = tunables.m_VisualReactionRange;
float audioReactionRange = tunables.m_AudioReactionRange;
float fEventEffectRange = pEvent->m_fEventRadius;
Vector3 vecEventPos;
u32 uStart = pEvent->GetStartTime();
if(tunables.m_DebugDisplayAlwaysUseEventPosition)
{
vecEventPos = RCC_VECTOR3(pEvent->m_vEventPosition);
}
else
{
if(pEvent->m_pEntitySource)
vecEventPos = VEC3V_TO_VECTOR3(pEvent->m_pEntitySource->GetTransform().GetPosition());
else
vecEventPos = RCC_VECTOR3(pEvent->m_vEventPosition);
}
if( RENDER_VECTOR_MAP )
{
switch(tunables.m_Priority)
{
case EInteresting:
{
if(RENDER_SHOCK_EVENT_LEVEL_INTERESTING)
{
if(RENDER_EVENT_EFFECT_AREA)
{
CVectorMap::DrawCircle(vecEventPos, fEventEffectRange, Color_white, false);
}
else
{
CVectorMap::DrawCircle(vecEventPos, audioReactionRange, Color_white, false);
CVectorMap::DrawCircle(vecEventPos, visualReactionRange, Color_grey80, false);
}
CVectorMap::DrawCircle(vecEventPos, 1.0f, Color_white, false);
}
}
break;
case EAffectsOthers:
{
if(RENDER_SHOCK_EVENT_LEVEL_AFFECTSOTHERS)
{
if(RENDER_EVENT_EFFECT_AREA)
{
CVectorMap::DrawCircle(vecEventPos, fEventEffectRange, Color_blue, false);
}
else
{
CVectorMap::DrawCircle(vecEventPos, audioReactionRange, Color_blue, false);
CVectorMap::DrawCircle(vecEventPos, visualReactionRange, Color_navy, false);
}
CVectorMap::DrawCircle(vecEventPos, 1.0f, Color_blue, false);
}
}
break;
case EPotentiallyDangerous:
{
if(RENDER_SHOCK_EVENT_LEVEL_POTENTIALLYDANGEROUS)
{
if(RENDER_EVENT_EFFECT_AREA)
{
CVectorMap::DrawCircle(vecEventPos, fEventEffectRange, Color_green, false);
}
else
{
CVectorMap::DrawCircle(vecEventPos, audioReactionRange, Color_green, false);
CVectorMap::DrawCircle(vecEventPos, visualReactionRange, Color_DarkGreen, false);
}
CVectorMap::DrawCircle(vecEventPos, 1.0f, Color_green, false);
}
}
break;
case ESeriousDanger:
{
if(RENDER_SHOCK_EVENT_LEVEL_SERIOUSDANGER)
{
if(RENDER_EVENT_EFFECT_AREA)
{
CVectorMap::DrawCircle(vecEventPos, fEventEffectRange, Color_red, false);
}
else
{
CVectorMap::DrawCircle(vecEventPos, audioReactionRange, Color_red, false);
CVectorMap::DrawCircle(vecEventPos, visualReactionRange, Color_OrangeRed, false);
}
CVectorMap::DrawCircle(vecEventPos, 1.0f, Color_red, false);
}
}
break;
default:
break;
}
}
if(RENDER_AS_LIST)
{
Color32 txtCol;
switch(tunables.m_Priority)
{
case EInteresting:
txtCol = Color_white;
break;
case EAffectsOthers:
txtCol = Color_blue;
break;
case EPotentiallyDangerous:
txtCol = Color_green;
break;
case ESeriousDanger:
txtCol = Color_red;
break;
default:
break;
}
const char* eventName = CEventNames::GetEventName(nEventType);
const char* pScriptInfo = "";
if(pEvent->GetCreatedByScript())
{
pScriptInfo = ", SCRIPT";
}
if(tunables.m_DebugDisplayListPlayerInfo
&& pEvent->m_pEntitySource
&& pEvent->m_pEntitySource->GetIsTypePed()
&& static_cast<CPed*>(pEvent->m_pEntitySource.Get())->IsPlayer())
{
formatf( debugText, "%d:%s: (%.2f, %.2f, %.2f), Created at time %u PLAYER%s", nEventsFound, eventName, vecEventPos.x, vecEventPos.y, vecEventPos.z, uStart, pScriptInfo );
}
else
{
formatf( debugText, "%d:%s: (%.2f, %.2f, %.2f), Created at time %u %s", nEventsFound, eventName, vecEventPos.x, vecEventPos.y, vecEventPos.z, uStart, pScriptInfo );
}
vTextRenderPos.y = ScreenCoors.y + (iNoOfTexts++)*fVertDist;
grcDebugDraw::Text(vTextRenderPos, txtCol, debugText);
}
if( RENDER_ON_3D_SCREEN )
{
switch(tunables.m_Priority)
{
case EInteresting:
{
if(RENDER_SHOCK_EVENT_LEVEL_INTERESTING)
{
if(RENDER_EVENT_EFFECT_AREA)
{
grcDebugDraw::Sphere( vecEventPos, fEventEffectRange, Color_white, false );
}
else
{
grcDebugDraw::Sphere( vecEventPos, audioReactionRange, Color_white, false );
grcDebugDraw::Sphere( vecEventPos, visualReactionRange, Color_grey, false );
}
grcDebugDraw::Sphere( vecEventPos, 1.0f, Color_white, true );
}
}
break;
case EAffectsOthers:
{
if(RENDER_SHOCK_EVENT_LEVEL_AFFECTSOTHERS)
{
if(RENDER_EVENT_EFFECT_AREA)
{
grcDebugDraw::Sphere( vecEventPos, fEventEffectRange, Color_blue, false );
}
else
{
grcDebugDraw::Sphere( vecEventPos, audioReactionRange, Color_blue, false );
grcDebugDraw::Sphere( vecEventPos, visualReactionRange, Color_cyan1, false );
}
grcDebugDraw::Sphere( vecEventPos, 1.0f, Color_blue, true );
}
}
break;
case EPotentiallyDangerous:
{
if(RENDER_SHOCK_EVENT_LEVEL_POTENTIALLYDANGEROUS)
{
if(RENDER_EVENT_EFFECT_AREA)
{
grcDebugDraw::Sphere( vecEventPos, fEventEffectRange, Color_green, false );
}
else
{
grcDebugDraw::Sphere( vecEventPos, audioReactionRange, Color_green, false );
grcDebugDraw::Sphere( vecEventPos, visualReactionRange, Color_yellow4, false );
}
grcDebugDraw::Sphere( vecEventPos, 1.0f, Color_green, true );
}
}
break;
case ESeriousDanger:
{
if(RENDER_SHOCK_EVENT_LEVEL_SERIOUSDANGER)
{
if(RENDER_EVENT_EFFECT_AREA)
{
if(nEventType == EVENT_SHOCKING_EXPLOSION || nEventType == EVENT_SHOCKING_GUN_FIGHT)
{
grcDebugDraw::Sphere( vecEventPos, fEventEffectRange, Color_red, false );
}
}
else
{
grcDebugDraw::Sphere( vecEventPos, audioReactionRange, Color_red, false );
grcDebugDraw::Sphere( vecEventPos, visualReactionRange, Color_orange, false );
}
grcDebugDraw::Sphere( vecEventPos, 1.0f, Color_red, true );
}
}
break;
default:
break;
}
}
}
}
#endif // __BANK
#if 0 // For reference, old function for converting weapon type.
eSEventTypes CShockingEventsManager::ConvertVisibleWeaponEType(u32 UNUSED_PARAM(nWeaponHash))
{
// CS - Removed because of hard coded WeaponType
// if(nWeaponHash==WEAPONTYPE_UNARMED || nWeaponHash == 0)
// return EVisibleWeapon;
//
// const CWeaponInfo *pWeaponInfo = CWeaponInfoManager::GetItemInfo<CWeaponInfo>(nWeaponHash);
// u32 iWeaponSlot = pWeaponInfo->GetSlot();
// if(iWeaponSlot == WEAPONSLOT_MELEE)
// {
// return EVisibleWeaponMELEE;
// }
// else if(iWeaponSlot == WEAPONSLOT_HANDGUN)
// {
// return EVisibleWeaponHANDGUN;
// }
// else if(iWeaponSlot == WEAPONSLOT_SHOTGUN)
// {
// return EVisibleWeaponSHOTGUN;
// }
// else if(iWeaponSlot == WEAPONSLOT_SMG)
// {
// return EVisibleWeaponSMG;
// }
// else if(iWeaponSlot == WEAPONSLOT_RIFLE)
// {
// return EVisibleWeaponRIFLE;
// }
// else if(iWeaponSlot == WEAPONSLOT_SNIPER)
// {
// return EVisibleWeaponSNIPER;
// }
// else if(iWeaponSlot == WEAPONSLOT_HEAVY)
// {
// return EVisibleWeaponHEAVY;
// }
// else if(iWeaponSlot == WEAPONSLOT_THROWN)
// {
// return EVisibleWeaponTHROWN;
// }
// else
{
return EVisibleWeapon;
}
}
#endif
//-----------------------------------------------------------------------------