commit
996bc0293f
@ -354,6 +354,7 @@ DebugMenuPopulate(void)
|
|||||||
#ifndef MASTER
|
#ifndef MASTER
|
||||||
DebugMenuAddVarBool8("Debug", "Toggle unused fight feature", (int8*)&CPed::bUnusedFightThingOnPlayer, nil);
|
DebugMenuAddVarBool8("Debug", "Toggle unused fight feature", (int8*)&CPed::bUnusedFightThingOnPlayer, nil);
|
||||||
DebugMenuAddVarBool8("Debug", "Toggle banned particles", (int8*)&CParticle::bEnableBannedParticles, nil);
|
DebugMenuAddVarBool8("Debug", "Toggle banned particles", (int8*)&CParticle::bEnableBannedParticles, nil);
|
||||||
|
DebugMenuAddVarBool8("Debug", "Toggle popping heads on headshot", (int8*)&CPed::bPopHeadsOnHeadshot, nil);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
DebugMenuAddCmd("Debug", "Start Credits", CCredits::Start);
|
DebugMenuAddCmd("Debug", "Start Credits", CCredits::Start);
|
||||||
|
@ -49,9 +49,6 @@ public:
|
|||||||
CVector2D operator+(const CVector2D &rhs) const {
|
CVector2D operator+(const CVector2D &rhs) const {
|
||||||
return CVector2D(x+rhs.x, y+rhs.y);
|
return CVector2D(x+rhs.x, y+rhs.y);
|
||||||
}
|
}
|
||||||
CVector2D operator*(float t) const {
|
|
||||||
return CVector2D(x*t, y*t);
|
|
||||||
}
|
|
||||||
CVector2D operator/(float t) const {
|
CVector2D operator/(float t) const {
|
||||||
return CVector2D(x/t, y/t);
|
return CVector2D(x/t, y/t);
|
||||||
}
|
}
|
||||||
@ -91,3 +88,13 @@ NormalizeXY(float &x, float &y)
|
|||||||
}else
|
}else
|
||||||
x = 1.0f;
|
x = 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline CVector2D operator*(const CVector2D &left, float right)
|
||||||
|
{
|
||||||
|
return CVector2D(left.x * right, left.y * right);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline CVector2D operator*(float left, const CVector2D &right)
|
||||||
|
{
|
||||||
|
return CVector2D(left * right.x, left * right.y);
|
||||||
|
}
|
||||||
|
381
src/peds/Ped.cpp
381
src/peds/Ped.cpp
@ -49,16 +49,12 @@
|
|||||||
#include "ParticleObject.h"
|
#include "ParticleObject.h"
|
||||||
#include "Floater.h"
|
#include "Floater.h"
|
||||||
|
|
||||||
WRAPPER void CPed::SpawnFlyingComponent(int, int8) { EAXJMP(0x4EB060); }
|
|
||||||
WRAPPER void CPed::SetPedPositionInCar(void) { EAXJMP(0x4D4970); }
|
|
||||||
WRAPPER void CPed::SetMoveAnim(void) { EAXJMP(0x4C5A40); }
|
WRAPPER void CPed::SetMoveAnim(void) { EAXJMP(0x4C5A40); }
|
||||||
WRAPPER void CPed::UpdatePosition(void) { EAXJMP(0x4C7A00); }
|
|
||||||
WRAPPER void CPed::WanderPath(void) { EAXJMP(0x4D28D0); }
|
WRAPPER void CPed::WanderPath(void) { EAXJMP(0x4D28D0); }
|
||||||
WRAPPER void CPed::SetEnterCar_AllClear(CVehicle*, uint32, uint32) { EAXJMP(0x4E0A40); }
|
WRAPPER void CPed::SetEnterCar_AllClear(CVehicle*, uint32, uint32) { EAXJMP(0x4E0A40); }
|
||||||
WRAPPER bool CPed::WarpPedToNearEntityOffScreen(CEntity*) { EAXJMP(0x4E5570); }
|
WRAPPER bool CPed::WarpPedToNearEntityOffScreen(CEntity*) { EAXJMP(0x4E5570); }
|
||||||
WRAPPER void CPed::SetObjective(eObjective, CVector) { EAXJMP(0x4D8A90); }
|
WRAPPER void CPed::SetObjective(eObjective, CVector) { EAXJMP(0x4D8A90); }
|
||||||
WRAPPER void CPed::SetObjective(eObjective, CVector, float) { EAXJMP(0x4D8770); }
|
WRAPPER void CPed::SetObjective(eObjective, CVector, float) { EAXJMP(0x4D8770); }
|
||||||
WRAPPER void CPed::WarpPedIntoCar(CVehicle*) { EAXJMP(0x4D7D20); }
|
|
||||||
WRAPPER void CPed::SetCarJack(CVehicle*) { EAXJMP(0x4E0220); }
|
WRAPPER void CPed::SetCarJack(CVehicle*) { EAXJMP(0x4E0220); }
|
||||||
WRAPPER void CPed::WarpPedToNearLeaderOffScreen(void) { EAXJMP(0x4E52A0); }
|
WRAPPER void CPed::WarpPedToNearLeaderOffScreen(void) { EAXJMP(0x4E52A0); }
|
||||||
|
|
||||||
@ -78,6 +74,8 @@ CPedAudioData (&CPed::CommentWaitTime)[38] = *(CPedAudioData(*)[38]) * (uintptr*
|
|||||||
|
|
||||||
uint16 nPlayerInComboMove;
|
uint16 nPlayerInComboMove;
|
||||||
|
|
||||||
|
RpClump *flyingClumpTemp;
|
||||||
|
|
||||||
// This is beta fistfite.dat array. Not used anymore since they're being fetched from fistfite.dat.
|
// This is beta fistfite.dat array. Not used anymore since they're being fetched from fistfite.dat.
|
||||||
FightMove tFightMoves[NUM_FIGHTMOVES] = {
|
FightMove tFightMoves[NUM_FIGHTMOVES] = {
|
||||||
{NUM_ANIMS, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0},
|
{NUM_ANIMS, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0},
|
||||||
@ -286,6 +284,7 @@ static char WaitStateText[][16] = {
|
|||||||
#ifndef MASTER
|
#ifndef MASTER
|
||||||
int nDisplayDebugInfo = 0;
|
int nDisplayDebugInfo = 0;
|
||||||
bool CPed::bUnusedFightThingOnPlayer = false;
|
bool CPed::bUnusedFightThingOnPlayer = false;
|
||||||
|
bool CPed::bPopHeadsOnHeadshot = false;
|
||||||
|
|
||||||
void
|
void
|
||||||
CPed::SwitchDebugDisplay(void)
|
CPed::SwitchDebugDisplay(void)
|
||||||
@ -878,7 +877,11 @@ CPed::RemoveBodyPart(PedNode nodeId, int8 direction)
|
|||||||
frame = GetNodeFrame(nodeId);
|
frame = GetNodeFrame(nodeId);
|
||||||
if (frame) {
|
if (frame) {
|
||||||
if (CGame::nastyGame) {
|
if (CGame::nastyGame) {
|
||||||
|
#ifndef MASTER
|
||||||
|
if (bPopHeadsOnHeadshot || nodeId != PED_HEAD)
|
||||||
|
#else
|
||||||
if (nodeId != PED_HEAD)
|
if (nodeId != PED_HEAD)
|
||||||
|
#endif
|
||||||
SpawnFlyingComponent(nodeId, direction);
|
SpawnFlyingComponent(nodeId, direction);
|
||||||
|
|
||||||
RecurseFrameChildrenVisibilityCB(frame, nil);
|
RecurseFrameChildrenVisibilityCB(frame, nil);
|
||||||
@ -1852,11 +1855,11 @@ CPed::LineUpPedWithCar(PedLineUpPhase phase)
|
|||||||
|
|
||||||
// Getting out
|
// Getting out
|
||||||
if (!veh->bIsBus || (veh->bIsBus && vehIsUpsideDown)) {
|
if (!veh->bIsBus || (veh->bIsBus && vehIsUpsideDown)) {
|
||||||
float pedZSpeedOnExit = m_vecMoveSpeed.z - 0.008f * CTimer::GetTimeStep();
|
float nextZSpeed = m_vecMoveSpeed.z - GRAVITY * CTimer::GetTimeStep();
|
||||||
|
|
||||||
// If we're not in ground at next step, apply animation
|
// If we're not in ground at next step, apply animation
|
||||||
if (neededPos.z + pedZSpeedOnExit >= autoZPos.z) {
|
if (neededPos.z + nextZSpeed >= autoZPos.z) {
|
||||||
m_vecMoveSpeed.z = pedZSpeedOnExit;
|
m_vecMoveSpeed.z = nextZSpeed;
|
||||||
ApplyMoveSpeed();
|
ApplyMoveSpeed();
|
||||||
// Removing below line breaks the animation
|
// Removing below line breaks the animation
|
||||||
neededPos.z = GetPosition().z;
|
neededPos.z = GetPosition().z;
|
||||||
@ -6893,8 +6896,8 @@ CPed::FinishLaunchCB(CAnimBlendAssociation *animAssoc, void *arg)
|
|||||||
}
|
}
|
||||||
#ifdef VC_PED_PORTS
|
#ifdef VC_PED_PORTS
|
||||||
if (ped->m_pCurrentPhysSurface) {
|
if (ped->m_pCurrentPhysSurface) {
|
||||||
ped->m_vecMoveSpeed.x += ((CPhysical*)ped->m_pCurrentPhysSurface)->m_vecMoveSpeed.x;
|
ped->m_vecMoveSpeed.x += ped->m_pCurrentPhysSurface->m_vecMoveSpeed.x;
|
||||||
ped->m_vecMoveSpeed.y += ((CPhysical*)ped->m_pCurrentPhysSurface)->m_vecMoveSpeed.y;
|
ped->m_vecMoveSpeed.y += ped->m_pCurrentPhysSurface->m_vecMoveSpeed.y;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -8330,8 +8333,7 @@ CPed::InvestigateEvent(void)
|
|||||||
bool
|
bool
|
||||||
CPed::IsPedDoingDriveByShooting(void)
|
CPed::IsPedDoingDriveByShooting(void)
|
||||||
{
|
{
|
||||||
if (this == FindPlayerPed() && GetWeapon()->m_eWeaponType == WEAPONTYPE_UZI) {
|
if (FindPlayerPed() == this && GetWeapon()->m_eWeaponType == WEAPONTYPE_UZI) {
|
||||||
|
|
||||||
if (TheCamera.Cams[TheCamera.ActiveCam].LookingLeft || TheCamera.Cams[TheCamera.ActiveCam].LookingRight)
|
if (TheCamera.Cams[TheCamera.ActiveCam].LookingLeft || TheCamera.Cams[TheCamera.ActiveCam].LookingRight)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -13638,7 +13640,7 @@ LocalPosForWalkAround(CVector2D colMin, CVector2D colMax, int walkAround, uint32
|
|||||||
bool
|
bool
|
||||||
CanWeSeeTheCorner(CVector2D dist, CVector2D fwdOffset)
|
CanWeSeeTheCorner(CVector2D dist, CVector2D fwdOffset)
|
||||||
{
|
{
|
||||||
// because if dist is more then 5 unit, fov isn't important, we want shortest way
|
// because fov isn't important if dist is more then 5 unit, we want shortest way
|
||||||
if (dist.Magnitude() > 5.0f)
|
if (dist.Magnitude() > 5.0f)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@ -13769,6 +13771,7 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj)
|
|||||||
CVector cornerToGo = CVector(10.0f, 10.0f, 10.0f);
|
CVector cornerToGo = CVector(10.0f, 10.0f, 10.0f);
|
||||||
int dirToGo;
|
int dirToGo;
|
||||||
m_walkAroundType = 0;
|
m_walkAroundType = 0;
|
||||||
|
int iWouldPreferGoingBack = 0; // 1:left 2:right
|
||||||
#endif
|
#endif
|
||||||
float adjustedCheckInterval = 0.7f * checkIntervalInDist;
|
float adjustedCheckInterval = 0.7f * checkIntervalInDist;
|
||||||
CVector posToCheck;
|
CVector posToCheck;
|
||||||
@ -13796,6 +13799,9 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj)
|
|||||||
if (goingToEnterCar && (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR)) {
|
if (goingToEnterCar && (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR)) {
|
||||||
cornerToGo = tl;
|
cornerToGo = tl;
|
||||||
m_walkAroundType = 1;
|
m_walkAroundType = 1;
|
||||||
|
|
||||||
|
if (m_vehEnterType == CAR_DOOR_LR)
|
||||||
|
iWouldPreferGoingBack = 1;
|
||||||
} else if(CanWeSeeTheCorner(tl, GetForward())){
|
} else if(CanWeSeeTheCorner(tl, GetForward())){
|
||||||
cornerToGo = tl;
|
cornerToGo = tl;
|
||||||
dirToGo = GetLocalDirection(tl);
|
dirToGo = GetLocalDirection(tl);
|
||||||
@ -13831,6 +13837,9 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj)
|
|||||||
if (goingToEnterCar && (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR)) {
|
if (goingToEnterCar && (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR)) {
|
||||||
cornerToGo = tr;
|
cornerToGo = tr;
|
||||||
m_walkAroundType = 2;
|
m_walkAroundType = 2;
|
||||||
|
|
||||||
|
if (m_vehEnterType == CAR_DOOR_RR)
|
||||||
|
iWouldPreferGoingBack = 2;
|
||||||
} else if (CanWeSeeTheCorner(tr, GetForward())) {
|
} else if (CanWeSeeTheCorner(tr, GetForward())) {
|
||||||
cornerToGo = tr;
|
cornerToGo = tr;
|
||||||
dirToGo = GetLocalDirection(tr);
|
dirToGo = GetLocalDirection(tr);
|
||||||
@ -13863,7 +13872,9 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj)
|
|||||||
#ifdef NEW_WALK_AROUND_ALGORITHM
|
#ifdef NEW_WALK_AROUND_ALGORITHM
|
||||||
else {
|
else {
|
||||||
CVector br = obj->GetMatrix() * CVector(adjustedColMax.x, adjustedColMin.y, 0.0f) - GetPosition();
|
CVector br = obj->GetMatrix() * CVector(adjustedColMax.x, adjustedColMin.y, 0.0f) - GetPosition();
|
||||||
if (br.Magnitude2D() < cornerToGo.Magnitude2D()) {
|
if (iWouldPreferGoingBack == 2)
|
||||||
|
m_walkAroundType = 4;
|
||||||
|
else if (br.Magnitude2D() < cornerToGo.Magnitude2D()) {
|
||||||
if (goingToEnterCar && (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR)) {
|
if (goingToEnterCar && (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR)) {
|
||||||
cornerToGo = br;
|
cornerToGo = br;
|
||||||
m_walkAroundType = 5;
|
m_walkAroundType = 5;
|
||||||
@ -13899,7 +13910,9 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj)
|
|||||||
#ifdef NEW_WALK_AROUND_ALGORITHM
|
#ifdef NEW_WALK_AROUND_ALGORITHM
|
||||||
else {
|
else {
|
||||||
CVector bl = obj->GetMatrix() * CVector(adjustedColMin.x, adjustedColMin.y, 0.0f) - GetPosition();
|
CVector bl = obj->GetMatrix() * CVector(adjustedColMin.x, adjustedColMin.y, 0.0f) - GetPosition();
|
||||||
if (bl.Magnitude2D() < cornerToGo.Magnitude2D()) {
|
if (iWouldPreferGoingBack == 1)
|
||||||
|
m_walkAroundType = 7;
|
||||||
|
else if (bl.Magnitude2D() < cornerToGo.Magnitude2D()) {
|
||||||
if (goingToEnterCar && (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR)) {
|
if (goingToEnterCar && (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR)) {
|
||||||
cornerToGo = bl;
|
cornerToGo = bl;
|
||||||
m_walkAroundType = 6;
|
m_walkAroundType = 6;
|
||||||
@ -14300,7 +14313,7 @@ CPed::ProcessEntityCollision(CEntity *collidingEnt, CColPoint *collidingPoints)
|
|||||||
m_ped_flagH10 = false;
|
m_ped_flagH10 = false;
|
||||||
bOnBoat = false;
|
bOnBoat = false;
|
||||||
} else {
|
} else {
|
||||||
m_pCurrentPhysSurface = collidingEnt;
|
m_pCurrentPhysSurface = (CPhysical*)collidingEnt;
|
||||||
collidingEnt->RegisterReference((CEntity**)&m_pCurrentPhysSurface);
|
collidingEnt->RegisterReference((CEntity**)&m_pCurrentPhysSurface);
|
||||||
m_vecOffsetFromPhysSurface = intersectionPoint.point - collidingEnt->GetPosition();
|
m_vecOffsetFromPhysSurface = intersectionPoint.point - collidingEnt->GetPosition();
|
||||||
m_pCurSurface = collidingEnt;
|
m_pCurSurface = collidingEnt;
|
||||||
@ -14505,7 +14518,7 @@ CPed::WillChat(CPed *stranger)
|
|||||||
}
|
}
|
||||||
if (m_nSurfaceTouched == SURFACE_TARMAC)
|
if (m_nSurfaceTouched == SURFACE_TARMAC)
|
||||||
return false;
|
return false;
|
||||||
if (this == stranger)
|
if (stranger == this)
|
||||||
return false;
|
return false;
|
||||||
if (m_nPedType == stranger->m_nPedType)
|
if (m_nPedType == stranger->m_nPedType)
|
||||||
return true;
|
return true;
|
||||||
@ -14784,7 +14797,7 @@ CPed::ProcessBuoyancy(void)
|
|||||||
float buoyancyLevel = (m_nPedState == PED_DEAD ? 1.8f : 1.1f);
|
float buoyancyLevel = (m_nPedState == PED_DEAD ? 1.8f : 1.1f);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (mod_Buoyancy.ProcessBuoyancy(this, 0.008f * m_fMass * buoyancyLevel, &buoyancyPoint, &buoyancyImpulse)) {
|
if (mod_Buoyancy.ProcessBuoyancy(this, GRAVITY * m_fMass * buoyancyLevel, &buoyancyPoint, &buoyancyImpulse)) {
|
||||||
m_flagD8 = true;
|
m_flagD8 = true;
|
||||||
CEntity *entity;
|
CEntity *entity;
|
||||||
CColPoint point;
|
CColPoint point;
|
||||||
@ -16209,6 +16222,338 @@ CPed::UpdateFromLeader(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CPed::UpdatePosition(void)
|
||||||
|
{
|
||||||
|
if (CReplay::IsPlayingBack() || !bIsStanding)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CVector2D velocityChange;
|
||||||
|
|
||||||
|
SetHeading(m_fRotationCur);
|
||||||
|
if (m_pCurrentPhysSurface) {
|
||||||
|
CVector2D velocityOfSurface;
|
||||||
|
CPhysical *curSurface = m_pCurrentPhysSurface;
|
||||||
|
if (!IsPlayer() && m_pCurrentPhysSurface->IsVehicle() && ((CVehicle*)m_pCurrentPhysSurface)->IsBoat()) {
|
||||||
|
|
||||||
|
// It seems R* didn't like m_vecOffsetFromPhysSurface for boats
|
||||||
|
CVector offsetToSurface = GetPosition() - curSurface->GetPosition();
|
||||||
|
offsetToSurface.z -= FEET_OFFSET;
|
||||||
|
|
||||||
|
CVector surfaceMoveVelocity = curSurface->m_vecMoveSpeed;
|
||||||
|
CVector surfaceTurnVelocity = CrossProduct(curSurface->m_vecTurnSpeed, offsetToSurface);
|
||||||
|
|
||||||
|
// Also we use that weird formula instead of friction if it's boat
|
||||||
|
float slideMult = -curSurface->m_vecTurnSpeed.MagnitudeSqr();
|
||||||
|
velocityOfSurface = slideMult * offsetToSurface * CTimer::GetTimeStep() + (surfaceTurnVelocity + surfaceMoveVelocity);
|
||||||
|
m_vecMoveSpeed.z = slideMult * offsetToSurface.z * CTimer::GetTimeStep() + (surfaceTurnVelocity.z + surfaceMoveVelocity.z);
|
||||||
|
} else {
|
||||||
|
velocityOfSurface = curSurface->GetSpeed(m_vecOffsetFromPhysSurface);
|
||||||
|
}
|
||||||
|
// Reminder: m_moved is displacement from walking/running.
|
||||||
|
velocityChange = m_moved + velocityOfSurface - m_vecMoveSpeed;
|
||||||
|
m_fRotationCur += curSurface->m_vecTurnSpeed.z * CTimer::GetTimeStep();
|
||||||
|
m_fRotationDest += curSurface->m_vecTurnSpeed.z * CTimer::GetTimeStep();
|
||||||
|
} else if (m_nSurfaceTouched != SURFACE_STONE || m_vecDamageNormal.x == 0.0f && m_vecDamageNormal.y == 0.0f) {
|
||||||
|
velocityChange = m_moved - m_vecMoveSpeed;
|
||||||
|
} else {
|
||||||
|
// Ped got damaged by steep slope
|
||||||
|
m_vecMoveSpeed = CVector(0.0f, 0.0f, -0.001f);
|
||||||
|
// some kind of
|
||||||
|
CVector2D reactionForce = m_vecDamageNormal * (1.0f / m_vecDamageNormal.Magnitude2D());
|
||||||
|
|
||||||
|
velocityChange = 0.02f * reactionForce + m_moved;
|
||||||
|
|
||||||
|
float reactionAndVelocityDotProd = DotProduct2D(reactionForce, velocityChange);
|
||||||
|
// they're in same direction
|
||||||
|
if (reactionAndVelocityDotProd < 0.0f) {
|
||||||
|
velocityChange -= reactionAndVelocityDotProd * reactionForce;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take time step into account
|
||||||
|
if (m_pCurrentPhysSurface) {
|
||||||
|
float speedChange = velocityChange.Magnitude();
|
||||||
|
float changeMult = speedChange;
|
||||||
|
if (m_nPedState != PED_DIE || !m_pCurrentPhysSurface->IsVehicle()) {
|
||||||
|
if (!m_pCurrentPhysSurface->IsVehicle() || !((CVehicle*)m_pCurrentPhysSurface)->IsBoat())
|
||||||
|
changeMult = 0.01f * CTimer::GetTimeStep();
|
||||||
|
} else {
|
||||||
|
changeMult = 0.002f * CTimer::GetTimeStep();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (speedChange > changeMult) {
|
||||||
|
velocityChange = velocityChange * (changeMult / speedChange);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_vecMoveSpeed.x += velocityChange.x;
|
||||||
|
m_vecMoveSpeed.y += velocityChange.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CPed::SetPedPositionInCar(void)
|
||||||
|
{
|
||||||
|
if (CReplay::IsPlayingBack())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (bChangedSeat) {
|
||||||
|
bool notYet = false;
|
||||||
|
if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_GETIN_LHS)
|
||||||
|
|| RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_GETIN_LOW_LHS)
|
||||||
|
|| RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_CLOSEDOOR_LHS)
|
||||||
|
|| RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_CLOSEDOOR_LOW_LHS)
|
||||||
|
|| RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_SHUFFLE_RHS)
|
||||||
|
|| RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_LSHUFFLE_RHS)
|
||||||
|
|| RpAnimBlendClumpGetAssociation(GetClump(), ANIM_VAN_CLOSE_L)
|
||||||
|
|| RpAnimBlendClumpGetAssociation(GetClump(), ANIM_VAN_CLOSE)
|
||||||
|
|| RpAnimBlendClumpGetAssociation(GetClump(), ANIM_VAN_GETIN_L)
|
||||||
|
|| RpAnimBlendClumpGetAssociation(GetClump(), ANIM_VAN_GETIN)
|
||||||
|
|| RpAnimBlendClumpGetAssociation(GetClump(), ANIM_COACH_IN_L)
|
||||||
|
|| RpAnimBlendClumpGetAssociation(GetClump(), ANIM_COACH_IN_R)) {
|
||||||
|
notYet = true;
|
||||||
|
}
|
||||||
|
if (notYet) {
|
||||||
|
LineUpPedWithCar(LINE_UP_TO_CAR_START);
|
||||||
|
bChangedSeat = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CVehicleModelInfo *vehModel = (CVehicleModelInfo*)CModelInfo::GetModelInfo(m_pMyVehicle->m_modelIndex);
|
||||||
|
CMatrix newMat(m_pMyVehicle->GetMatrix());
|
||||||
|
CVector seatPos;
|
||||||
|
if (m_pMyVehicle->pDriver == this) {
|
||||||
|
if (vehModel->m_vehicleType == VEHICLE_TYPE_BOAT)
|
||||||
|
seatPos = vehModel->m_positions[BOAT_POS_FRONTSEAT];
|
||||||
|
else
|
||||||
|
seatPos = vehModel->m_positions[CAR_POS_FRONTSEAT];
|
||||||
|
|
||||||
|
if (!m_pMyVehicle->IsBoat() && m_pMyVehicle->m_vehType != VEHICLE_TYPE_BIKE)
|
||||||
|
seatPos.x = -seatPos.x;
|
||||||
|
|
||||||
|
} else if (m_pMyVehicle->pPassengers[0] == this) {
|
||||||
|
if (vehModel->m_vehicleType == VEHICLE_TYPE_BOAT)
|
||||||
|
seatPos = vehModel->m_positions[BOAT_POS_FRONTSEAT];
|
||||||
|
else
|
||||||
|
seatPos = vehModel->m_positions[CAR_POS_FRONTSEAT];
|
||||||
|
} else if (m_pMyVehicle->pPassengers[1] == this) {
|
||||||
|
seatPos = vehModel->m_positions[CAR_POS_BACKSEAT];
|
||||||
|
seatPos.x = -seatPos.x;
|
||||||
|
} else {
|
||||||
|
if (m_pMyVehicle->pPassengers[2] == this) {
|
||||||
|
seatPos = vehModel->m_positions[CAR_POS_BACKSEAT];
|
||||||
|
} else if (vehModel->m_vehicleType == VEHICLE_TYPE_BOAT) {
|
||||||
|
seatPos = vehModel->m_positions[BOAT_POS_FRONTSEAT];
|
||||||
|
} else {
|
||||||
|
seatPos = vehModel->m_positions[CAR_POS_FRONTSEAT];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newMat.GetPosition() += Multiply3x3(newMat, seatPos);
|
||||||
|
// Already done below (SetTranslate(0.0f, 0.0f, 0.0f))
|
||||||
|
// tempMat.SetUnity();
|
||||||
|
|
||||||
|
// Rear seats on vans don't face to front, so rotate them HALFPI.
|
||||||
|
if (m_pMyVehicle->bIsVan) {
|
||||||
|
CMatrix tempMat;
|
||||||
|
if (m_pMyVehicle->pPassengers[1] == this) {
|
||||||
|
m_fRotationCur = m_pMyVehicle->GetForward().Heading() - HALFPI;
|
||||||
|
tempMat.SetTranslate(0.0f, 0.0f, 0.0f);
|
||||||
|
tempMat.RotateZ(-HALFPI);
|
||||||
|
newMat = newMat * tempMat;
|
||||||
|
} else if (m_pMyVehicle->pPassengers[2] == this) {
|
||||||
|
m_fRotationCur = HALFPI + m_pMyVehicle->GetForward().Heading();
|
||||||
|
tempMat.SetTranslate(0.0f, 0.0f, 0.0f);
|
||||||
|
tempMat.RotateZ(HALFPI);
|
||||||
|
newMat = newMat * tempMat;
|
||||||
|
} else {
|
||||||
|
m_fRotationCur = m_pMyVehicle->GetForward().Heading();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m_fRotationCur = m_pMyVehicle->GetForward().Heading();
|
||||||
|
}
|
||||||
|
GetMatrix() = newMat;
|
||||||
|
}
|
||||||
|
|
||||||
|
static RwObject*
|
||||||
|
CloneAtomicToFrameCB(RwObject *frame, void *data)
|
||||||
|
{
|
||||||
|
RpAtomic *newAtomic = RpAtomicClone((RpAtomic*)frame);
|
||||||
|
RpAtomicSetFrame(newAtomic, (RwFrame*)data);
|
||||||
|
RpClumpAddAtomic(flyingClumpTemp, newAtomic);
|
||||||
|
CVisibilityPlugins::SetAtomicRenderCallback(newAtomic, nil);
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
static RwFrame*
|
||||||
|
RecurseFrameChildrenToCloneCB(RwFrame *frame, void *data)
|
||||||
|
{
|
||||||
|
RwFrame *newFrame = RwFrameCreate();
|
||||||
|
RwFrameAddChild((RwFrame*)data, newFrame);
|
||||||
|
RwFrameTransform(newFrame, RwFrameGetMatrix(frame), rwCOMBINEREPLACE);
|
||||||
|
RwFrameForAllObjects(frame, CloneAtomicToFrameCB, newFrame);
|
||||||
|
RwFrameForAllChildren(frame, RecurseFrameChildrenToCloneCB, newFrame);
|
||||||
|
return newFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
CObject*
|
||||||
|
CPed::SpawnFlyingComponent(int pedNode, int8 direction)
|
||||||
|
{
|
||||||
|
if (CObject::nNoTempObjects >= NUMTEMPOBJECTS)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
CObject *obj = new CObject();
|
||||||
|
if (!obj)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
RwFrame *frame = RwFrameCreate();
|
||||||
|
RpClump *clump = RpClumpCreate();
|
||||||
|
RpClumpSetFrame(clump, frame);
|
||||||
|
RwMatrix *matrix = RwFrameGetLTM(GetNodeFrame(pedNode));
|
||||||
|
*RwFrameGetMatrix(frame) = *matrix;
|
||||||
|
|
||||||
|
flyingClumpTemp = clump;
|
||||||
|
RwFrameForAllObjects(GetNodeFrame(pedNode), CloneAtomicToFrameCB, frame);
|
||||||
|
RwFrameForAllChildren(GetNodeFrame(pedNode), RecurseFrameChildrenToCloneCB, frame);
|
||||||
|
flyingClumpTemp = nil;
|
||||||
|
switch (pedNode) {
|
||||||
|
case PED_HEAD:
|
||||||
|
// So popping head would have wheel collision. They disabled it anyway
|
||||||
|
obj->SetModelIndexNoCreate(MI_CAR_WHEEL);
|
||||||
|
break;
|
||||||
|
case PED_UPPERARML:
|
||||||
|
case PED_UPPERARMR:
|
||||||
|
obj->SetModelIndexNoCreate(MI_BODYPARTB);
|
||||||
|
obj->SetCenterOfMass(0.25f, 0.0f, 0.0f);
|
||||||
|
break;
|
||||||
|
case PED_UPPERLEGL:
|
||||||
|
case PED_UPPERLEGR:
|
||||||
|
obj->SetModelIndexNoCreate(MI_BODYPARTA);
|
||||||
|
obj->SetCenterOfMass(0.4f, 0.0f, 0.0f);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
obj->RefModelInfo(m_modelIndex);
|
||||||
|
obj->AttachToRwObject((RwObject*)clump);
|
||||||
|
obj->m_fMass = 15.0f;
|
||||||
|
obj->m_fTurnMass = 5.0f;
|
||||||
|
obj->m_fAirResistance = 0.99f;
|
||||||
|
obj->m_fElasticity = 0.03f;
|
||||||
|
obj->m_fBuoyancy = m_fMass*GRAVITY/0.75f;
|
||||||
|
obj->ObjectCreatedBy = TEMP_OBJECT;
|
||||||
|
obj->bIsStatic = false;
|
||||||
|
obj->bIsPickup = false;
|
||||||
|
obj->m_nSpecialCollisionResponseCases = COLLRESPONSE_SPLIT_MODEL;
|
||||||
|
|
||||||
|
// life time - the more objects the are, the shorter this one will live
|
||||||
|
CObject::nNoTempObjects++;
|
||||||
|
if (CObject::nNoTempObjects > 20)
|
||||||
|
obj->m_nEndOfLifeTime = CTimer::GetTimeInMilliseconds() + 12000;
|
||||||
|
else if (CObject::nNoTempObjects > 10)
|
||||||
|
obj->m_nEndOfLifeTime = CTimer::GetTimeInMilliseconds() + 30000;
|
||||||
|
else
|
||||||
|
obj->m_nEndOfLifeTime = CTimer::GetTimeInMilliseconds() + 60000;
|
||||||
|
|
||||||
|
CVector localForcePos, forceDir;
|
||||||
|
|
||||||
|
if (direction == 2) {
|
||||||
|
obj->m_vecMoveSpeed = 0.03f * GetForward();
|
||||||
|
obj->m_vecMoveSpeed.z = (CGeneral::GetRandomNumber() & 0x3F) * 0.001f;
|
||||||
|
obj->m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f);
|
||||||
|
localForcePos = CVector(0.0f, 0.0f, 0.0f);
|
||||||
|
forceDir = GetForward();
|
||||||
|
} else {
|
||||||
|
obj->m_vecMoveSpeed = -0.03f * GetForward();
|
||||||
|
obj->m_vecMoveSpeed.z = (CGeneral::GetRandomNumber() & 0x3F) * 0.001f;
|
||||||
|
obj->m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f);
|
||||||
|
localForcePos = CVector(0.0f, 0.0f, 0.0f);
|
||||||
|
forceDir = -GetForward();
|
||||||
|
}
|
||||||
|
obj->ApplyTurnForce(forceDir, localForcePos);
|
||||||
|
CWorld::Add(obj);
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CPed::WarpPedIntoCar(CVehicle *car)
|
||||||
|
{
|
||||||
|
bInVehicle = true;
|
||||||
|
m_pMyVehicle = car;
|
||||||
|
m_pMyVehicle->RegisterReference((CEntity **) &m_pMyVehicle);
|
||||||
|
m_carInObjective = car;
|
||||||
|
m_carInObjective->RegisterReference((CEntity **) &m_carInObjective);
|
||||||
|
m_nPedState = PED_DRIVING;
|
||||||
|
bUsesCollision = false;
|
||||||
|
bIsInTheAir = false;
|
||||||
|
m_ped_flagI4 = true;
|
||||||
|
if (m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) {
|
||||||
|
car->SetDriver(this);
|
||||||
|
car->pDriver->RegisterReference((CEntity **) &car->pDriver);
|
||||||
|
|
||||||
|
} else if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER) {
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
if (!car->pPassengers[i]) {
|
||||||
|
car->pPassengers[i] = this;
|
||||||
|
car->pPassengers[i]->RegisterReference((CEntity **) &car->pPassengers[i]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (IsPlayer()) {
|
||||||
|
car->m_status = STATUS_PLAYER;
|
||||||
|
AudioManager.PlayerJustGotInCar();
|
||||||
|
CCarCtrl::RegisterVehicleOfInterest(car);
|
||||||
|
} else {
|
||||||
|
car->m_status = STATUS_PHYSICS;
|
||||||
|
}
|
||||||
|
|
||||||
|
CWorld::Remove(this);
|
||||||
|
GetPosition() = car->GetPosition();
|
||||||
|
CWorld::Add(this);
|
||||||
|
|
||||||
|
if (car->bIsAmbulanceOnDuty) {
|
||||||
|
car->bIsAmbulanceOnDuty = false;
|
||||||
|
--CCarCtrl::NumAmbulancesOnDuty;
|
||||||
|
}
|
||||||
|
if (car->bIsFireTruckOnDuty) {
|
||||||
|
car->bIsFireTruckOnDuty = false;
|
||||||
|
--CCarCtrl::NumFiretrucksOnDuty;
|
||||||
|
}
|
||||||
|
if (!car->bEngineOn) {
|
||||||
|
car->bEngineOn = true;
|
||||||
|
DMAudio.PlayOneShot(car->m_audioEntityId, SOUND_CAR_ENGINE_START, 1.0f);
|
||||||
|
}
|
||||||
|
if (car->IsBoat()) {
|
||||||
|
m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_DRIVE_BOAT, 100.0f);
|
||||||
|
CWeaponInfo *ourWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType);
|
||||||
|
RemoveWeaponModel(ourWeapon->m_nModelId);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Because we can use Uzi for drive by
|
||||||
|
// RemoveWeaponWhenEnteringVehicle in VC
|
||||||
|
if (IsPlayer() && HasWeapon(WEAPONTYPE_UZI) && GetWeapon(WEAPONTYPE_UZI).m_nAmmoTotal > 0) {
|
||||||
|
if (m_storedWeapon == WEAPONTYPE_UNIDENTIFIED)
|
||||||
|
m_storedWeapon = GetWeapon()->m_eWeaponType;
|
||||||
|
SetCurrentWeapon(WEAPONTYPE_UZI);
|
||||||
|
} else {
|
||||||
|
CWeaponInfo *ourWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType);
|
||||||
|
RemoveWeaponModel(ourWeapon->m_nModelId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (car->bLowVehicle)
|
||||||
|
m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_LSIT, 100.0f);
|
||||||
|
else
|
||||||
|
m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_SIT, 100.0f);
|
||||||
|
}
|
||||||
|
StopNonPartialAnims();
|
||||||
|
if (car->bIsBus)
|
||||||
|
bRenderPedInCar = false;
|
||||||
|
|
||||||
|
bChangedSeat = true;
|
||||||
|
}
|
||||||
|
|
||||||
class CPed_ : public CPed
|
class CPed_ : public CPed
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -16430,4 +16775,6 @@ STARTPATCHES
|
|||||||
InjectHook(0x4E5870, &CPed::ServiceTalking, PATCH_JUMP);
|
InjectHook(0x4E5870, &CPed::ServiceTalking, PATCH_JUMP);
|
||||||
InjectHook(0x4E7780, &CPed::StartFightDefend, PATCH_JUMP);
|
InjectHook(0x4E7780, &CPed::StartFightDefend, PATCH_JUMP);
|
||||||
InjectHook(0x4D8F30, &CPed::UpdateFromLeader, PATCH_JUMP);
|
InjectHook(0x4D8F30, &CPed::UpdateFromLeader, PATCH_JUMP);
|
||||||
|
InjectHook(0x4D4970, &CPed::SetPedPositionInCar, PATCH_JUMP);
|
||||||
|
InjectHook(0x4D7D20, &CPed::WarpPedIntoCar, PATCH_JUMP);
|
||||||
ENDPATCHES
|
ENDPATCHES
|
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
struct CPathNode;
|
struct CPathNode;
|
||||||
class CAccident;
|
class CAccident;
|
||||||
|
class CObject;
|
||||||
|
|
||||||
struct CPedAudioData
|
struct CPedAudioData
|
||||||
{
|
{
|
||||||
@ -362,7 +363,7 @@ public:
|
|||||||
|
|
||||||
uint8 bShakeFist : 1; // test shake hand at look entity
|
uint8 bShakeFist : 1; // test shake hand at look entity
|
||||||
uint8 bNoCriticalHits : 1; // if set, limbs won't came off
|
uint8 bNoCriticalHits : 1; // if set, limbs won't came off
|
||||||
uint8 m_ped_flagI4 : 1; // seems like related with cars
|
uint8 m_ped_flagI4 : 1; // we've been put to car by script? - related with cars
|
||||||
uint8 bHasAlreadyBeenRecorded : 1;
|
uint8 bHasAlreadyBeenRecorded : 1;
|
||||||
uint8 bFallenDown : 1;
|
uint8 bFallenDown : 1;
|
||||||
#ifdef VC_PED_PORTS
|
#ifdef VC_PED_PORTS
|
||||||
@ -430,7 +431,7 @@ public:
|
|||||||
float m_headingRate;
|
float m_headingRate;
|
||||||
uint16 m_vehEnterType; // TODO: this is more like a door, not a type
|
uint16 m_vehEnterType; // TODO: this is more like a door, not a type
|
||||||
int16 m_walkAroundType;
|
int16 m_walkAroundType;
|
||||||
CEntity *m_pCurrentPhysSurface;
|
CPhysical *m_pCurrentPhysSurface;
|
||||||
CVector m_vecOffsetFromPhysSurface;
|
CVector m_vecOffsetFromPhysSurface;
|
||||||
CEntity *m_pCurSurface;
|
CEntity *m_pCurSurface;
|
||||||
CVector m_vecSeekPos;
|
CVector m_vecSeekPos;
|
||||||
@ -532,7 +533,6 @@ public:
|
|||||||
void SetDead(void);
|
void SetDead(void);
|
||||||
void ApplyHeadShot(eWeaponType weaponType, CVector pos, bool evenOnPlayer);
|
void ApplyHeadShot(eWeaponType weaponType, CVector pos, bool evenOnPlayer);
|
||||||
void RemoveBodyPart(PedNode nodeId, int8 direction);
|
void RemoveBodyPart(PedNode nodeId, int8 direction);
|
||||||
void SpawnFlyingComponent(int, int8);
|
|
||||||
bool OurPedCanSeeThisOne(CEntity *target);
|
bool OurPedCanSeeThisOne(CEntity *target);
|
||||||
void Avoid(void);
|
void Avoid(void);
|
||||||
void Attack(void);
|
void Attack(void);
|
||||||
@ -670,7 +670,6 @@ public:
|
|||||||
void ProcessBuoyancy(void);
|
void ProcessBuoyancy(void);
|
||||||
void ServiceTalking(void);
|
void ServiceTalking(void);
|
||||||
void SetJump(void);
|
void SetJump(void);
|
||||||
void UpdatePosition(void);
|
|
||||||
void WanderPath(void);
|
void WanderPath(void);
|
||||||
void ReactToPointGun(CEntity*);
|
void ReactToPointGun(CEntity*);
|
||||||
void SeekCar(void);
|
void SeekCar(void);
|
||||||
@ -767,6 +766,8 @@ public:
|
|||||||
void WanderRange(void);
|
void WanderRange(void);
|
||||||
void SetFollowRoute(int16, int16);
|
void SetFollowRoute(int16, int16);
|
||||||
void SeekBoatPosition(void);
|
void SeekBoatPosition(void);
|
||||||
|
void UpdatePosition(void);
|
||||||
|
CObject *SpawnFlyingComponent(int, int8);
|
||||||
#ifdef VC_PED_PORTS
|
#ifdef VC_PED_PORTS
|
||||||
bool CanPedJumpThis(CEntity*, CVector*);
|
bool CanPedJumpThis(CEntity*, CVector*);
|
||||||
#else
|
#else
|
||||||
@ -796,9 +797,12 @@ public:
|
|||||||
static CPedAudioData (&CommentWaitTime)[38];
|
static CPedAudioData (&CommentWaitTime)[38];
|
||||||
|
|
||||||
#ifndef MASTER
|
#ifndef MASTER
|
||||||
|
static bool bUnusedFightThingOnPlayer;
|
||||||
|
static bool bPopHeadsOnHeadshot;
|
||||||
|
|
||||||
|
// Mobile things
|
||||||
static void SwitchDebugDisplay(void);
|
static void SwitchDebugDisplay(void);
|
||||||
void DebugRenderOnePedText(void);
|
void DebugRenderOnePedText(void);
|
||||||
static bool bUnusedFightThingOnPlayer;
|
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2474,8 +2474,8 @@ CAutomobile::TankControl(void)
|
|||||||
int lifeSpan = 250;
|
int lifeSpan = 250;
|
||||||
if(m_vecMoveSpeed.Magnitude() > 0.08f){
|
if(m_vecMoveSpeed.Magnitude() > 0.08f){
|
||||||
lifeSpan = 125;
|
lifeSpan = 125;
|
||||||
flashPos.x += 0.5f*m_vecMoveSpeed.x;
|
flashPos.x += 5.0f*m_vecMoveSpeed.x;
|
||||||
flashPos.y += 0.5f*m_vecMoveSpeed.y;
|
flashPos.y += 5.0f*m_vecMoveSpeed.y;
|
||||||
}
|
}
|
||||||
CParticle::AddParticle(PARTICLE_GUNFLASH, flashPos, nullDir, nil, 0.4f, black, 0, 0, 0, lifeSpan);
|
CParticle::AddParticle(PARTICLE_GUNFLASH, flashPos, nullDir, nil, 0.4f, black, 0, 0, 0, lifeSpan);
|
||||||
flashPos += 0.3f*shotDir;
|
flashPos += 0.3f*shotDir;
|
||||||
@ -4210,7 +4210,7 @@ CAutomobile::SpawnFlyingComponent(int32 component, uint32 type)
|
|||||||
if(atomic == nil)
|
if(atomic == nil)
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
obj = new CObject;
|
obj = new CObject();
|
||||||
if(obj == nil)
|
if(obj == nil)
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user