int CLuaVector3Defs::Cross ( lua_State* luaVM )
{
    CLuaVector3D* pVector1 = NULL;
    CLuaVector3D* pVector2 = NULL;

    CScriptArgReader argStream ( luaVM );
    argStream.ReadUserData ( pVector1 );
    argStream.ReadUserData ( pVector2 );

    if ( !argStream.HasErrors () )
    {
        CVector vector ( *pVector1 );
        vector.CrossProduct ( pVector2 );
        
        lua_pushvector ( luaVM, vector );
        return 1;
    }
    else
    {
        m_pScriptDebugging->LogCustom ( luaVM, argStream.GetFullErrorMessage() );
    }

    lua_pushboolean ( luaVM, false );
    return 1;
}
Exemple #2
0
bool CClientCamera::ProcessFixedCamera ( CCam* pCam )
{
    // The purpose of this handler function is changing the Source, Front and Up vectors in CCam
    // when called by GTA. This is called when we are in fixed camera mode.

    CClientCamera* pThis = g_pClientGame->GetManager ()->GetCamera ();

    // Make sure we actually want to apply our custom camera position/lookat
    // (this handler could also be called from cinematic mode)
    if ( !pThis->m_bFixed )
        return false;

    const CVector& vecPosition = pThis->m_vecFixedPosition;
    const CVector& vecTarget = pThis->m_vecFixedTarget;

    // Set the position in the CCam interface
    *pCam->GetSource () = vecPosition;

    // Calculate the front vector, target - position. If its length is 0 we'll get problems
    // (i.e. if position and target are the same), so make a new vector then looking horizontally
    CVector vecFront = vecTarget - vecPosition;
    if ( vecFront.Length () < FLOAT_EPSILON )
        vecFront = CVector ( 0.0, 1.0f, 0.0f );
    else
        vecFront.Normalize ();

    *pCam->GetFront () = vecFront;

    // Grab the right vector
    CVector vecRight = CVector ( vecFront.fY, -vecFront.fX, 0 );
    if ( vecRight.Length () < FLOAT_EPSILON )
        vecRight = CVector ( 1.0f, 0.0f, 0.0f );
    else
        vecRight.Normalize ();

    // Calculate the up vector from this
    CVector vecUp = vecRight;
    vecUp.CrossProduct ( &vecFront );
    vecUp.Normalize ();

    // Apply roll if needed
    if ( pThis->m_fRoll != 0.0f )
    {
        float fRoll = ConvertDegreesToRadiansNoWrap ( pThis->m_fRoll );
        vecUp = vecUp*cos(fRoll) - vecRight*sin(fRoll);
    }

    *pCam->GetUp () = vecUp;

    // Set the zoom
    pCam->SetFOV ( pThis->m_fFOV );

    return true;
}
Exemple #3
0
void CClientSound::Process3D ( CVector vecPosition, CVector vecLookAt )
{
    if ( !m_b3D ) return;

    // Update our position/rotation if we're attached
    DoAttaching ();

    if ( m_pSound )
    {
        // Pan
        CVector vecLook = vecLookAt - vecPosition;
        CVector vecSound = m_vecPosition - vecPosition;
        vecLook.fZ = vecSound.fZ = 0.0f;
        vecLook.Normalize ();
        vecSound.Normalize ();

        vecLook.CrossProduct ( &vecSound );
        // The length of the cross product (which is simply fZ in this case)
        // is equal to the sine of the angle between the vectors
        float fPan = vecLook.fZ;
        if ( fPan < -1.0f + SOUND_PAN_THRESHOLD )
            fPan = -1.0f + SOUND_PAN_THRESHOLD;
        else if ( fPan > 1.0f - SOUND_PAN_THRESHOLD )
            fPan = 1.0f - SOUND_PAN_THRESHOLD;

        m_pSound->setPan ( fPan );

        // Volume
        float fDistance = DistanceBetweenPoints3D ( vecPosition, m_vecPosition );
        float fSilenceDistance = m_fMinDistance * 20.0f;
        float fVolume = 1.0;

        if ( fDistance <= m_fMinDistance )
        {
            fVolume = 1.0f;
        }
        else if ( fDistance >= fSilenceDistance )
        {
            fVolume = 0.0f;
        }
        else
        {
            float fLinear = (fSilenceDistance - fDistance) / fSilenceDistance;
            fVolume = sqrt ( fLinear ) * fLinear;
        }

        m_pSound->setVolume ( m_fVolume * fVolume );
    }
}
Exemple #4
0
void CBassAudio::Process3D ( const CVector& vecPlayerPosition, const CVector& vecCameraPosition, const CVector& vecLookAt )
{
    assert ( m_b3D && m_pSound );

    float fDistance = DistanceBetweenPoints3D ( vecCameraPosition, m_vecPosition );
    if ( m_bPan )
    {
        // Limit panning when getting close to the min distance
        float fPanSharpness = UnlerpClamped ( m_fMinDistance, fDistance, m_fMinDistance * 2 );
        float fPanLimit = Lerp ( 0.35f, fPanSharpness, 1.0f );

        // Pan
        CVector vecLook = vecLookAt - vecCameraPosition;
        CVector vecSound = m_vecPosition - vecCameraPosition;
        vecLook.fZ = vecSound.fZ = 0.0f;
        vecLook.Normalize ();
        vecSound.Normalize ();

        vecLook.CrossProduct ( &vecSound );
        // The length of the cross product (which is simply fZ in this case)
        // is equal to the sine of the angle between the vectors
        float fPan = Clamp ( -fPanLimit, -vecLook.fZ, fPanLimit );

        BASS_ChannelSetAttribute( m_pSound, BASS_ATTRIB_PAN, fPan );
    }
    else
    {
        // Revert to middle.
        BASS_ChannelSetAttribute( m_pSound, BASS_ATTRIB_PAN, 0.0f );
    }

    // Volume
    float fDistDiff = m_fMaxDistance - m_fMinDistance;

    //Transform e^-x to suit our sound
    float fVolume;
    if ( fDistance <= m_fMinDistance )
        fVolume = 1.0f;
    else if ( fDistance >= m_fMaxDistance )
        fVolume = 0.0f;
    else
        fVolume = exp ( - ( fDistance - m_fMinDistance ) * ( CUT_OFF / fDistDiff ) );

    BASS_ChannelSetAttribute( m_pSound, BASS_ATTRIB_VOL, fVolume * m_fVolume );
}
Exemple #5
0
void CClientCamera::SetFixedTarget ( const CVector& vecPosition, float fRoll )
{
    // Switch to fixed mode if required
    if ( !IsInFixedMode () )        
        ToggleCameraFixedMode ( true );

    // Store the target so it can be updated from our hook
    m_vecFixedTarget = vecPosition;
    m_fRoll = fRoll;
    m_FixedCameraMode = EFixedCameraMode::TARGET;

    // Update fixed matrix
    // Calculate the front vector, target - position. If its length is 0 we'll get problems
    // (i.e. if position and target are the same), so make a new vector then looking horizontally
    CVector vecFront = m_vecFixedTarget - m_matFixedMatrix.vPos;
    if ( vecFront.Length () < FLOAT_EPSILON )
        vecFront = CVector ( 0.0, 1.0f, 0.0f );
    else
        vecFront.Normalize ();

    // Grab the right vector
    CVector vecRight = CVector ( vecFront.fY, -vecFront.fX, 0 );
    if ( vecRight.Length () < FLOAT_EPSILON )
        vecRight = CVector ( 1.0f, 0.0f, 0.0f );
    else
        vecRight.Normalize ();

    // Calculate the up vector from this
    CVector vecUp = vecRight;
    vecUp.CrossProduct ( &vecFront );
    vecUp.Normalize ();

    // Apply roll if needed
    if ( m_fRoll != 0.0f )
    {
        float fRoll = ConvertDegreesToRadiansNoWrap ( m_fRoll );
        vecUp = vecUp*cos(fRoll) - vecRight*sin(fRoll);
    }

    // Set rotational part of fixed matrix
    m_matFixedMatrix.vFront = vecFront;
    m_matFixedMatrix.vUp = vecUp;
    m_matFixedMatrix.OrthoNormalize( CMatrix::AXIS_FRONT, CMatrix::AXIS_UP );
}
/////////////////////////////////////////////////////////////
//
// CAdditionalVertexStreamManager::UpdateAdditionalStreamContent
//
// Generate data in the additional stream
//
/////////////////////////////////////////////////////////////
bool CAdditionalVertexStreamManager::UpdateAdditionalStreamContent ( SCurrentStateInfo& state, SAdditionalStreamInfo* pAdditionalInfo, uint ReadOffsetStart, uint ReadSize, uint WriteOffsetStart, uint WriteSize )
{
    //HRESULT hr;
    IDirect3DVertexBuffer9* pStreamDataPT = state.stream1.pStreamData;
    IDirect3DVertexBuffer9* pStreamDataN = pAdditionalInfo->pStreamData;
    uint StridePT = 20;
    uint StrideN = 12;
    uint NumVerts = ReadSize / StridePT;
    assert ( NumVerts == WriteSize / StrideN );

    // Get the source vertex bytes
    std::vector < uchar > sourceArray;
    sourceArray.resize ( ReadSize );
    uchar* pSourceArrayBytes = &sourceArray[0];
    {
        void* pVertexBytesPT = NULL;
        if ( FAILED( pStreamDataPT->Lock ( ReadOffsetStart, ReadSize, &pVertexBytesPT, D3DLOCK_NOSYSLOCK | D3DLOCK_READONLY ) ) )
            return false;
        memcpy ( pSourceArrayBytes, pVertexBytesPT, ReadSize );
        pStreamDataPT->Unlock ();
    }

    // Create dest byte buffer
    std::vector < uchar > destArray;
    destArray.resize ( WriteSize );
    uchar* pDestArrayBytes = &destArray[0];

    // Compute dest bytes
    {
        // Get index buffer
        if ( FAILED( m_pDevice->GetIndices( &state.pIndexData ) ) )
            return false;

        // Get index buffer desc
        D3DINDEXBUFFER_DESC IndexBufferDesc;
        state.pIndexData->GetDesc ( &IndexBufferDesc );

        uint numIndices = state.args.primCount + 2;
        uint step = 1;
        if ( state.args.PrimitiveType == D3DPT_TRIANGLELIST )
        {
            numIndices = state.args.primCount * 3;
            step = 3;
        }
        assert ( IndexBufferDesc.Size >= ( numIndices + state.args.startIndex ) * 2 );

        // Get index buffer data
        std::vector < uchar > indexArray;
        indexArray.resize ( ReadSize );
        uchar* pIndexArrayBytes = &indexArray[0];
        {
            void* pIndexBytes = NULL;
            if ( FAILED( state.pIndexData->Lock ( state.args.startIndex*2, numIndices*2, &pIndexBytes, D3DLOCK_NOSYSLOCK | D3DLOCK_READONLY ) ) )
                return false;
            memcpy ( pIndexArrayBytes, pIndexBytes, numIndices*2 );
            state.pIndexData->Unlock ();
        }

        // Calc normals
        std::vector < CVector > NormalList;
        NormalList.insert ( NormalList.end (), NumVerts, CVector () );

        std::map < long long, CVector > doneTrisMap;

        // For each triangle
        for ( uint i = 0 ; i < numIndices - 2 ; i += step )
        {
            // Get triangle vertex indici
            WORD v0 = ((WORD*)pIndexArrayBytes)[ i ];
            WORD v1 = ((WORD*)pIndexArrayBytes)[ i + 1 ];
            WORD v2 = ((WORD*)pIndexArrayBytes)[ i + 2 ];

            if ( v0 >= NumVerts || v1 >= NumVerts || v2 >= NumVerts )
                continue;   // vert index out of range

            if ( v0 == v1 || v0 == v2 || v1 == v2 )
                continue;   // degenerate tri

            // Get vertex positions from original stream
            CVector* pPos0 = (CVector*)( pSourceArrayBytes + v0 * 20 );
            CVector* pPos1 = (CVector*)( pSourceArrayBytes + v1 * 20 );
            CVector* pPos2 = (CVector*)( pSourceArrayBytes + v2 * 20 );

            // Calculate the normal
            CVector Dir1 = *pPos2 - *pPos1;
            CVector Dir2 = *pPos0 - *pPos1;

            CVector Normal = Dir1;
            Normal.CrossProduct ( &Dir2 );
            Normal.Normalize ();

            // Flip normal if triangle was flipped
            if ( state.args.PrimitiveType == D3DPT_TRIANGLESTRIP && ( i & 1 ) )
                Normal = -Normal;

            // Try to improve results by ignoring duplicated triangles
            long long key = getTriKey ( v0, v1, v2 );
            if ( CVector* pDoneTriPrevNormal = MapFind ( doneTrisMap, key ) )
            {
                // Already done this tri - Keep prev tri if it has a better 'up' rating
                if ( pDoneTriPrevNormal->fZ > Normal.fZ )
                    continue;

                // Remove effect of prev tri
                NormalList[ v0 ] -= *pDoneTriPrevNormal;
                NormalList[ v1 ] -= *pDoneTriPrevNormal;
                NormalList[ v2 ] -= *pDoneTriPrevNormal;
            }
            MapSet ( doneTrisMap, key, Normal );

            // Add normal weight to used vertices
            NormalList[ v0 ] += Normal;
            NormalList[ v1 ] += Normal;
            NormalList[ v2 ] += Normal;
        }

        // Validate normals and set dest data
        for ( uint i = 0 ; i < NumVerts ; i++ )
        {
            // Validate
            CVector& Normal = NormalList[i];
            if ( Normal.Normalize () < FLOAT_EPSILON )
                Normal = CVector ( 0, 0, 1 );

            // Set
            CVector* pNormal = (CVector*)( pDestArrayBytes + i * 12 );
            *pNormal = Normal;
        }
    }

    // Set the dest bytes
    {
        void* pVertexBytesN = NULL;
        if ( FAILED( pStreamDataN->Lock ( WriteOffsetStart, WriteSize, &pVertexBytesN, D3DLOCK_NOSYSLOCK ) ) )
            return false;
        memcpy ( pVertexBytesN, pDestArrayBytes, WriteSize );
        pStreamDataN->Unlock ();
    }

    return true;
}
////////////////////////////////////////////////////////////////
//
// CMaterialLine3DBatcher::DrawBatch
//
// Create vertices and draw
//
////////////////////////////////////////////////////////////////
void CMaterialLine3DBatcher::DrawBatch(const CVector& vecCameraPos, uint* pBatchIndices, uint uiNumBatchLines, CMaterialItem* pMaterial)
{
    // Prepare vertex buffer
    std::vector<SPDTVertex> vertices;
    vertices.resize(uiNumBatchLines * 6);
    SPDTVertex* pBuffer = &vertices[0];

    // For each line
    for (uint i = 0; i < uiNumBatchLines; i++)
    {
        const SMaterialLine3DItem& item = m_LineList[pBatchIndices[i]];

        SColor color = item.ulColor;
        if (m_bPreGUI)
        {
            color.R /= 2;
            color.G /= 2;
            color.B /= 2;
        }
        const ulong    ulColor = color;
        const CVector& vecA = item.vecFrom;
        const CVector& vecB = item.vecTo;

        const CVector& vecFaceToward = item.bUseFaceToward ? item.vecFaceToward : vecCameraPos;

        // Face toward supplied point
        const CVector vecDif = vecB - vecA;
        const CVector vecToCam = vecFaceToward - vecA;
        const float   t = vecDif.DotProduct(&vecToCam) / vecDif.DotProduct(&vecDif);
        const CVector vecClosestPoint = vecA + vecDif * t;
        const CVector vecToLine = vecClosestPoint - vecFaceToward;

        // Calc other direction
        CVector vecLeft = vecDif;
        vecLeft.CrossProduct(&vecToLine);
        vecLeft.Normalize();

        // Create rectangle points
        const CVector vecShift = vecLeft * (item.fWidth * 0.5f);
        const CVector vecA2 = item.vecFrom + vecShift;
        const CVector vecB2 = item.vecTo + vecShift;
        const CVector vecA1 = item.vecFrom - vecShift;
        const CVector vecB1 = item.vecTo - vecShift;

        WRITE_PDT_VERTEX(pBuffer, vecA1.fX, vecA1.fY, vecA1.fZ, ulColor, item.fU1, item.fV1);
        WRITE_PDT_VERTEX(pBuffer, vecA2.fX, vecA2.fY, vecA2.fZ, ulColor, item.fU2, item.fV1);
        WRITE_PDT_VERTEX(pBuffer, vecB1.fX, vecB1.fY, vecB1.fZ, ulColor, item.fU1, item.fV2);

        WRITE_PDT_VERTEX(pBuffer, vecA2.fX, vecA2.fY, vecA2.fZ, ulColor, item.fU2, item.fV1);
        WRITE_PDT_VERTEX(pBuffer, vecB2.fX, vecB2.fY, vecB2.fZ, ulColor, item.fU2, item.fV2);
        WRITE_PDT_VERTEX(pBuffer, vecB1.fX, vecB1.fY, vecB1.fZ, ulColor, item.fU1, item.fV2);
    }

    // Set vertex stream
    uint        PrimitiveCount = vertices.size() / 3;
    const void* pVertexStreamZeroData = &vertices[0];
    uint        VertexStreamZeroStride = sizeof(SPDTVertex);
    m_pDevice->SetFVF(SPDTVertex::FVF);

    // Change texture addressing mode if required
    if (m_CurrentTextureAddress != pMaterial->m_TextureAddress)
    {
        m_CurrentTextureAddress = pMaterial->m_TextureAddress;
        m_pDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, m_CurrentTextureAddress);
        m_pDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, m_CurrentTextureAddress);
    }

    if (m_CurrentTextureAddress == TADDRESS_BORDER)
        m_pDevice->SetSamplerState(0, D3DSAMP_BORDERCOLOR, pMaterial->m_uiBorderColor);

    // Draw
    if (CTextureItem* pTextureItem = DynamicCast<CTextureItem>(pMaterial))
    {
        // Draw using texture
        m_pDevice->SetTexture(0, pTextureItem->m_pD3DTexture);
        m_pDevice->DrawPrimitiveUP(D3DPT_TRIANGLELIST, PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
    }
    else if (CShaderInstance* pShaderInstance = DynamicCast<CShaderInstance>(pMaterial))
    {
        // Draw using shader
        ID3DXEffect* pD3DEffect = pShaderInstance->m_pEffectWrap->m_pD3DEffect;

        // Apply custom parameters
        pShaderInstance->ApplyShaderParameters();
        // Apply common parameters
        pShaderInstance->m_pEffectWrap->ApplyCommonHandles();
        // Apply mapped parameters
        pShaderInstance->m_pEffectWrap->ApplyMappedHandles();

        // Do shader passes
        DWORD dwFlags = D3DXFX_DONOTSAVESHADERSTATE;            // D3DXFX_DONOTSAVE(SHADER|SAMPLER)STATE
        uint  uiNumPasses = 0;
        pShaderInstance->m_pEffectWrap->Begin(&uiNumPasses, dwFlags);

        for (uint uiPass = 0; uiPass < uiNumPasses; uiPass++)
        {
            pD3DEffect->BeginPass(uiPass);
            m_pDevice->DrawPrimitiveUP(D3DPT_TRIANGLELIST, PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
            pD3DEffect->EndPass();
        }
        pShaderInstance->m_pEffectWrap->End();

        // If we didn't get the effect to save the shader state, clear some things here
        if (dwFlags & D3DXFX_DONOTSAVESHADERSTATE)
        {
            m_pDevice->SetVertexShader(NULL);
            m_pDevice->SetPixelShader(NULL);
        }
    }
}
Exemple #8
0
bool CD3DMGEng::DrawLine3D ( const D3DXVECTOR3& a, const D3DXVECTOR3& b, float fWidth, LPDIRECT3DTEXTURE9 pTexture, DWORD dwColor )
{
    D3DSPRITEVERTEX3D *pVertices;

    ////////////////////////////////////////////////////
    // Make sure we have a valid vertex buffer.
    if ( m_pVB == NULL )
        return false;
    
    if ( a == b )
        return false;

    ///////////////////////////////////////////////////
    // Setup the rendering.
    m_pDevice->SetFVF ( D3DFVF_SPRITEVERTEX3DTEX );
    m_pDevice->SetStreamSource ( 0, m_pVB, 0, sizeof(D3DSPRITEVERTEX3D) );
    m_pDevice->SetTexture ( 0, pTexture );

    CVector vecA ( a.x, a.y, a.z );
    CVector vecB ( b.x, b.y, b.z );
    CVector vecDir = vecB - vecA;
    vecDir.Normalize ();
    CVector vecUpInit ( 0.0f, 0.0f, 1.0f );
    CVector vecUp;

    if ( fabs(vecDir.fX) > 0.0001f || fabs(vecDir.fY) > 0.0001f )
    {
        D3DXMATRIX ViewMatrix;
        CDirect3DData::GetSingleton ( ).GetTransform ( D3DTS_VIEW, &ViewMatrix );
        CVector vecCameraLookDir(ViewMatrix._13, ViewMatrix._23, ViewMatrix._33);
        vecUp = vecDir;
        vecUp.CrossProduct ( &vecCameraLookDir );
    }
    else
    {
        vecUp = CVector ( 0.0f, 1.0f, 0.0f );
    }

    CVector vecShift = vecUp * (fWidth / 2.0f);
    CVector vecA2 = vecA + vecShift;
    CVector vecB2 = vecB + vecShift;
    vecA = vecA - vecShift;
    vecB = vecB - vecShift;

    //////////////////////////////////////////////////
    // Lock the vertex buffer and copy in the verts.
    m_pVB->Lock( 0, 0, (void**)&pVertices, 0 );
    {
        pVertices[0].fX =       vecA.fX;
        pVertices[0].fY =       vecA.fY;
        pVertices[0].fZ =       vecA.fZ;
        pVertices[0].tu =       0.0f;
        pVertices[0].tv =       0.0f;
        pVertices[0].dwColor =  dwColor;

        pVertices[1].fX =       vecA2.fX;
        pVertices[1].fY =       vecA2.fY;
        pVertices[1].fZ =       vecA2.fZ;
        pVertices[1].tu =       0.0f;
        pVertices[1].tv =       1.0f;
        pVertices[1].dwColor =  dwColor;

        pVertices[2].fX =       vecB.fX;
        pVertices[2].fY =       vecB.fY;
        pVertices[2].fZ =       vecB.fZ;
        pVertices[2].tu =       1.0f;
        pVertices[2].tv =       0.0f;
        pVertices[2].dwColor =  dwColor;

        pVertices[3].fX =       vecB2.fX;
        pVertices[3].fY =       vecB2.fY;
        pVertices[3].fZ =       vecB2.fZ;
        pVertices[3].tu =       1.0f;
        pVertices[3].tv =       1.0f;
        pVertices[3].dwColor =  dwColor;
    }
    m_pVB->Unlock();

    m_pDevice->SetRenderState ( D3DRS_CULLMODE, D3DCULL_NONE );
    /*
    m_pDevice->SetRenderState ( D3DRS_ALPHATESTENABLE, false );
    m_pDevice->SetRenderState ( D3DRS_STENCILENABLE, false );
    m_pDevice->SetRenderState ( D3DRS_CLIPPLANEENABLE, false );
    m_pDevice->SetRenderState ( D3DRS_SRCBLEND, D3DBLEND_ONE );
    m_pDevice->SetRenderState ( D3DRS_DESTBLEND, D3DBLEND_ZERO );
    */


    ////////////////////////////////////////////////////
    // Draw!
    m_pDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );

    m_pDevice->SetTexture( 0, NULL );

    return true;
}
void cheat_handle_quickwarp(struct vehicle_info *vehicle_info, struct actor_info *actor_info)
{
	if (KEYCOMBO_PRESSED(set.key_quickwarp))
	{
		CCam *pCam = pGame->GetCamera()->GetCam(pGame->GetCamera()->GetActiveCam());
		CVector camsrc(*pCam->GetSource()), src, target, tppos;
		CColPoint *pCollision = nullptr;
		CEntitySAInterface *pEntity = nullptr;

		if (pCam->GetMode() == MODE_AIMWEAPON || pCam->GetMode() == MODE_AIMWEAPON_ATTACHED || pCam->GetMode() == MODE_AIMWEAPON_FROMCAR)
		{
			// calculate target position by aim vector
			pGame->GetCamera()->Find3rdPersonCamTargetVector(700.0f, &camsrc, &src, &target);
		}
		else
		{
			// else by camera vector
			target = camsrc + *pCam->GetFront() * 700.0f;
		}

		// ignore self vehicle
		if (vehicle_info != nullptr)
		{
			*(::vehicle_info **)VAR_IgnoredEntity = vehicle_info;
		}

		if (GTAfunc_ProcessLineOfSight(&camsrc, &target, &pCollision, &pEntity, true, true, false, true, true, false, false, false))
		{
			tppos = *pCollision->GetPosition();
			tppos -= (*pCollision->GetNormal()) * 0.5f;
			
			if (pCollision->GetNormal()->fZ >= 0.5f || pPedSelf->GetAreaCode() != 0)
			{
				tppos.fZ += 1.0f;
				tppos.fZ = pGameInterface->GetWorld()->FindGroundZFor3DPosition(&tppos);
			}
			else
			{
				tppos.fZ = pGameInterface->GetWorld()->FindGroundZForPosition(tppos.fX, tppos.fY);
			}

			if (vehicle_info != nullptr)
			{
				// check for collision
				CVehicle *vehSelf = pPedSelf->GetVehicle();
				if (vehSelf)
				{
					pCollision->Destroy();
					// check for collision
					CVector vecVehicleGravity;
					vehSelf->GetGravity(&vecVehicleGravity);
					CVector vecVehicleAbove = (-vecVehicleGravity * 5.0f) + tppos;
					CVector vecVehicleBelow = (vecVehicleGravity * 5.0f) + tppos;
					bool bCollision = GTAfunc_ProcessLineOfSight(&vecVehicleAbove, &vecVehicleBelow, &pCollision, &pEntity,
																 true, false, false, true, true, false, false, false); // not checking for vehicle collisions
					if (bCollision && pCollision)
					{
						// set vehicle to same Up position has surface normal
						CMatrix matVehicleSelf;
						vehSelf->GetMatrix(&matVehicleSelf);
						CVector vecCollisionNormal = *pCollision->GetNormal();

						// get "down" from vehicle model
						CVector rotationAxis = matVehicleSelf.vUp;

						// normalize our vectors
						vecCollisionNormal.Normalize();
						rotationAxis.Normalize();

						// axis and rotation for gravity
						float	theta = acos(rotationAxis.DotProduct(&vecCollisionNormal));
						if (!near_zero(theta))
						{
							rotationAxis.CrossProduct(&vecCollisionNormal);
							rotationAxis.Normalize();
							rotationAxis.ZeroNearZero();
							matVehicleSelf = matVehicleSelf.Rotate(&rotationAxis, -theta);
						}

						// set the new matrix
						vehSelf->SetMatrix(&matVehicleSelf);

						// set pos floats for actual teleporting
						tppos.fX = pCollision->GetPosition()->fX;
						tppos.fY = pCollision->GetPosition()->fY;
						tppos.fZ = pCollision->GetPosition()->fZ + 1.0f; // should be enough to stay above the ground properly
					}
					else
					{
						tppos.fZ += 0.5f;
					}
					cheat_vehicle_teleport(vehicle_info, &tppos.fX, gta_interior_id_get(), true);
				}
			}
			else if (actor_info != nullptr)
			{
				tppos.fZ += 1.0f;
				cheat_actor_teleport(actor_info, &tppos.fX, gta_interior_id_get());
			}
			GTAfunc_TogglePlayerControllable(0);
			GTAfunc_LockActor(0);
		}
		if (pCollision != nullptr)
		{
			pCollision->Destroy();
		}
	}
}
Exemple #10
0
void cheat_handle_actor_fly ( struct actor_info *ainfo, double time_diff )
{
	traceLastFunc( "cheat_handle_actor_fly()" );

	// toggle
	if ( KEY_PRESSED(set.key_fly_player) )
	{
		if ( !cheat_state->actor.fly_on )
		{
			cheat_state->actor.fly_on = 1;
		}
		else 
		{
			cheat_state->actor.fly_on = 0;
		}
	}

	if ( cheat_state->actor.fly_on )
	{

		// set fly status
		cheat_state->actor.fly_enabled = true;

		// get ground Z height
		float groundZHeight = pGame->GetWorld()->FindGroundZFor3DPosition(pPedSelf->GetPosition());
		float playerZHeight = pPedSelf->GetPosition()->fZ;
		float playerFrontZOffset = abs(pPedSelfSA->Placeable.matrix->vFront.fZ);
		float playerRightZOffset = abs(pPedSelfSA->Placeable.matrix->vRight.fZ);

		// standing detection
		if ( cheat_state->actor.fly_active
				&& ainfo->pedFlags.bIsStanding
			|| !KEY_DOWN(set.key_fly_player_strafeUp)
				&& cheat_state->actor.fly_active
				&& groundZHeight + 1.4f > playerZHeight
				&& groundZHeight - 1.4f < playerZHeight)
		{
			cheat_state->actor.fly_active = false;
			playerFly_lastKeySpeedState = speed_none;

			// remove up speed hard limiter patch
			if (patch_RemoveFlyUpSpeedLimit.installed)
			{
				patcher_remove(&patch_RemoveFlyUpSpeedLimit);
			}
			// remove fly soft limiters patch
			if (patch_RemoveFlyWindSpeedLimit.installed)
			{
				patcher_remove(&patch_RemoveFlyWindSpeedLimit);
			}

			// set gravity down
			pPedSelf->SetGravity( &-g_vecUpNormal );

			// copy camera rotation to player
			ainfo->fCurrentRotation = -pGame->GetCamera()->GetCameraRotation();
			ainfo->fTargetRotation = ainfo->fCurrentRotation;
			// play landing animation
			playerFly_lastAnimationStates = SHP_Jump_Land;
			GTAfunc_PerformAnimation("SHOP", "SHP_Jump_Land ", -1, 0, 1, 0, 0, 0, 0, 0);

			// correct for angle after landing if needed
			if (playerFrontZOffset > 0.4f
				|| playerRightZOffset > 0.3f)
			{
				// get player matrix
				CMatrix matPed;
				pPedSelf->GetMatrix(&matPed);

				// tilt player upright
				CVector rotationAxis = g_vecUpNormal;
				rotationAxis.CrossProduct( &matPed.vUp );
				float theta = ( matPed.vUp.DotProduct( &g_vecUpNormal ) );
				if ( !near_zero(theta) )
				{
					matPed = matPed.Rotate( &rotationAxis, cos(theta) );
					// normalize everything
					matPed.vFront.Normalize();
					matPed.vRight.Normalize();
					matPed.vUp.Normalize();
					// zero near zero
					matPed.vFront.ZeroNearZero();
					matPed.vRight.ZeroNearZero();
					matPed.vUp.ZeroNearZero();
					// set player matrix
					pPedSelf->SetMatrix(&matPed);
				}
			}
		}
		else if ( ainfo->pedFlags.bIsStanding
			|| !KEY_DOWN(set.key_fly_player_strafeUp)
				&& groundZHeight + 1.6f > playerZHeight
				&& groundZHeight - 1.6f < playerZHeight )
		{
			// still standing

			// update the last matrix
			pPedSelf->GetMatrix(&playerFly_lastPedRotation);
		}
		else if ( time_diff < 1.0f ) // I believe I can fly...
		{

// keys/buttons input

			playerFly_keySpeedStates keySpeedState;
			if ( KEY_DOWN(set.key_fly_player_accelerate) )
			{
				keySpeedState = speed_accelerate;
			}
			else if ( KEY_DOWN(set.key_fly_player_decelerate) )
			{
				keySpeedState = speed_decelerate;
			}
			else
			{
				keySpeedState = speed_none;
			}
			playerFly_keyStrafeStates keyStrafeState;
			if ( KEY_DOWN(set.key_fly_player_strafeLeft) && !KEY_DOWN(set.key_fly_player_strafeRight) )
			{
				keyStrafeState = strafe_left;
				playerFly_animationStrafeStateTimer = GetTickCount();
			}
			else if ( KEY_DOWN(set.key_fly_player_strafeRight) && !KEY_DOWN(set.key_fly_player_strafeLeft) )
			{
				keyStrafeState = strafe_right;
				playerFly_animationStrafeStateTimer = GetTickCount();
			}
			else if ( KEY_DOWN(set.key_fly_player_strafeUp) )
			{
				keyStrafeState = strafe_up;
				playerFly_animationStrafeStateTimer = GetTickCount();
			}
			else
			{
				keyStrafeState = strafe_none;
			}

			// activate fly mode
			if ( !cheat_state->actor.fly_active )
			{
				cheat_state->actor.fly_active = true;
				// install up speed hard limiter patch
				if (!patch_RemoveFlyUpSpeedLimit.installed)
				{
					patcher_install(&patch_RemoveFlyUpSpeedLimit);
				}
				// install fly soft limiters patch
				if (!patch_RemoveFlyWindSpeedLimit.installed)
				{
					patcher_install(&patch_RemoveFlyWindSpeedLimit);
				}
				if ( keySpeedState == speed_none )
				{
					// start fly animation
					GTAfunc_PerformAnimation("SWIM", "Swim_Tread", -1, 1, 1, 0, 0, 0, 1, 0);
					playerFly_lastAnimationStates = anim_Swim_Tread;
				}
			}

// init variables

			// setup variables used through this function
			CVector vecSpeed, rotationAxis;
			float theta, thetaBase, rotationMultiplier;
			pPedSelf->GetMoveSpeed(&vecSpeed);
			float speed = vecSpeed.Length();

			// copy camera rotation to player
			// this doesn't seem to be needed anymore
			//ainfo->fCurrentRotation = -pGame->GetCamera()->GetCameraRotation();

			// get camera matrix
			CMatrix matCamera;
			pGame->GetCamera()->GetMatrix(&matCamera);
			matCamera.vRight = -matCamera.vRight; // for some reason this is inverted
			// normalize camera
			matCamera.vFront.Normalize();
			matCamera.vRight.Normalize();
			matCamera.vUp.Normalize();

// change animation

			if ( playerFly_lastKeyStrafeStates != keyStrafeState
				|| playerFly_lastKeySpeedState != keySpeedState )
			{
				playerFly_lastKeyStrafeStates = keyStrafeState;
				playerFly_lastKeySpeedState = keySpeedState;
				playerFly_animationDeceleration = false;
				switch ( keySpeedState )
				{
				case speed_none:
					{
						if (playerFly_lastAnimationStates != anim_Swim_Breast)
						{
							playerFly_lastAnimationStates = anim_Swim_Breast;
							GTAfunc_PerformAnimation("SWIM", "Swim_Breast", -1, 1, 1, 0, 0, 0, 1, 0);
						}
						break;
					}
				case speed_accelerate:
					{
						if (playerFly_lastAnimationStates != anim_FALL_skyDive_accel)
						{
							playerFly_lastAnimationStates = anim_FALL_skyDive_accel;
							GTAfunc_PerformAnimation("PARACHUTE", "FALL_skyDive_accel", -1, 1, 1, 0, 0, 0, 1, 0);
						}
						break;
					}
				case speed_decelerate:
					{
						switch ( keyStrafeState )
						{
						case strafe_none:
						case strafe_up:
						case strafe_left:
						case strafe_right:
							{
								if ( speed > 0.45f )
								{
									if (playerFly_lastAnimationStates != anim_FALL_skyDive)
									{
										playerFly_lastAnimationStates = anim_FALL_skyDive;
										GTAfunc_PerformAnimation("PARACHUTE", "FALL_skyDive", -1, 1, 1, 0, 0, 0, 1, 0);
									}
									playerFly_animationDeceleration = true;
								}
								else if (playerFly_lastAnimationStates != anim_Swim_Tread)
								{
									playerFly_lastAnimationStates = anim_Swim_Tread;
									GTAfunc_PerformAnimation("SWIM", "Swim_Tread", -1, 1, 1, 0, 0, 0, 1, 0);
								}
							}
							break;
						default:
							{
								if (playerFly_lastAnimationStates != anim_Swim_Tread)
								{
									playerFly_lastAnimationStates = anim_Swim_Tread;
									GTAfunc_PerformAnimation("SWIM", "Swim_Tread", -1, 1, 1, 0, 0, 0, 1, 0);
								}
								break;
							}
						}
						break;
					}
				}
				playerFly_animationKeyStateSpeedDownChanged = false;
			}
			else if (!playerFly_animationKeyStateSpeedDownChanged)
			{
				switch ( keySpeedState )
				{
				case speed_decelerate:
					{
						if ( speed < 0.45f )
						{
							if (playerFly_lastAnimationStates != anim_Swim_Tread)
							{
								playerFly_lastAnimationStates = anim_Swim_Tread;
								GTAfunc_PerformAnimation("SWIM", "Swim_Tread", -1, 1, 1, 0, 0, 0, 1, 0);
							}
							playerFly_animationDeceleration = false;
							playerFly_animationKeyStateSpeedDownChanged = true;
						}
						break;
					}
				default:
					break;
				}
			}

// acceleration/deceleration

			// acceleration
			float fly_speed_max;
			float fly_acceleration;
			float fly_speed = set.fly_player_speed;
			float fly_acceleration_multiplier = set.fly_player_accel_multiplier;
			float fly_deceleration_multiplier = set.fly_player_decel_multiplier;
			switch ( keySpeedState )
			{
			case speed_accelerate:
				{
					if (fly_speed >= 1.0f)
					{
						fly_speed_max = 1.333f * (1.0f + (0.5f / fly_speed)) * fly_speed;
						fly_acceleration = time_diff * ((0.5f + (0.25f / (fly_speed / 4.0f))) * fly_speed) * fly_acceleration_multiplier;
					}
					else
					{
						fly_speed_max = 1.333f * (1.0f + (0.5f * fly_speed)) * fly_speed;
						fly_acceleration = time_diff * ((0.5f + fly_speed) * fly_speed) * fly_acceleration_multiplier;
					}

					if ( vecSpeed.Length() < fly_speed_max )
					{
						vecSpeed += matCamera.vFront * fly_acceleration;
					}

					// don't have NearZero speeds
					if ( !vecSpeed.IsNearZero() )
					{
						// set speed vector
						ainfo->m_SpeedVec = vecSpeed;
					}

				}
				break;
			case speed_none:
				{
					if (fly_speed >= 1.0f)
					{
						fly_speed_max = 0.1f;
						fly_acceleration = time_diff * 0.3f;
					}
					else
					{
						fly_speed_max = 0.1f * fly_speed;
						fly_acceleration = time_diff * (0.3f * fly_speed);
					}

					if ( vecSpeed.Length() < fly_speed_max )
					{
						vecSpeed += matCamera.vFront * fly_acceleration;
					}

					// calculate wind resistance
					float windResistance;
					float windSpeedDivisor = 1.5f;
					if (fly_speed >= windSpeedDivisor)
					{
						windResistance = time_diff * ( ( (fly_speed * 0.023f) + (speed * (fly_speed / (fly_speed / windSpeedDivisor)) * 0.38f) ) / (fly_speed / windSpeedDivisor) );
					}
					else if (fly_speed >= 1.0f)
					{
						windResistance = time_diff * ( ( (fly_speed * 0.023f) + (speed * (fly_speed / (fly_speed / windSpeedDivisor)) * 0.38f) ) * (fly_speed / windSpeedDivisor) );
					}
					else
					{
						windResistance = time_diff * ( ( (fly_speed * 0.023f) + (speed * 0.38f) ) * fly_speed );
					}
					vecSpeed -= vecSpeed * windResistance;

					// don't have NearZero speeds
					if ( !vecSpeed.IsNearZero() )
					{
						// set speed vector
						ainfo->m_SpeedVec = vecSpeed;
					}
				}
				break;
			case speed_decelerate:
				{
					// this bit should be converted to mta-style code
					vect3_normalize( ainfo->speed, ainfo->speed );

					speed -= time_diff * ((0.1f + speed) * (0.45f / (fly_speed / 2.0f)) * fly_speed) * fly_deceleration_multiplier;

					if ( speed < 0.0f )
						speed = 0.0f;

					if ( vect3_near_zero(ainfo->speed) )
					{
						vect3_zero( ainfo->speed );
					}
					else
					{
						vect3_mult( ainfo->speed, speed, ainfo->speed );
					}
				}
				break;
			}

// set speed target

			// calculate the desired speed target
			CVector vecSpeedRotate = matCamera.vFront;

			switch ( keyStrafeState )
			{
			case strafe_up:
				{
					vecSpeedRotate = matCamera.vUp;
				}
				break;
			case strafe_left:
				{
					CMatrix matTargetRotate;
					// rotate sideways
					matTargetRotate.vFront = vecSpeedRotate;
					rotationAxis = matCamera.vUp;
					theta = -1.57;
					matTargetRotate = matTargetRotate.Rotate( &rotationAxis, theta );
					// rotate upward
					rotationAxis = matCamera.vFront;
					if (KEY_DOWN(set.key_fly_player_strafeUp))
					{
						theta = -0.785;
					}
					else
					{
						theta = -0.05;
					}
					matTargetRotate = matTargetRotate.Rotate( &rotationAxis, theta );
					// set the rotation target
					vecSpeedRotate = matTargetRotate.vFront;
					vecSpeedRotate.Normalize();
				}
				break;
			case strafe_right:
				{
					CMatrix matTargetRotate;
					// rotate sideways
					matTargetRotate.vFront = vecSpeedRotate;
					rotationAxis = matCamera.vUp;
					theta = 1.57;
					matTargetRotate = matTargetRotate.Rotate( &rotationAxis, theta );
					// rotate upward
					rotationAxis = matCamera.vFront;
					if (KEY_DOWN(set.key_fly_player_strafeUp))
					{
						theta = 0.785;
					}
					else
					{
						theta = 0.05;
					}
					matTargetRotate = matTargetRotate.Rotate( &rotationAxis, theta );
					// set the rotation target
					vecSpeedRotate = matTargetRotate.vFront;
					vecSpeedRotate.Normalize();
				}
				break;
			case strafe_none:
				break;
			}

// rotate the speed

			CVector frontCamOffsetTarget;

			// rotate the speed vector slowly to face the desired target
			CMatrix matSpeedVecRotate;
			matSpeedVecRotate.vFront = vecSpeed;
			matSpeedVecRotate.vFront.Normalize();
			// calculate rotation multiplier, time_diff * 69.0 is ideal for calculations, always time for 69
			rotationMultiplier = (time_diff * 69.0f) / ( 32.0f + (vecSpeed.Length() * 5.0f) );
			// calculate rotation
			rotationAxis = vecSpeedRotate;// + gravCamPed_vecCameraPanOffset;
			rotationAxis.Normalize();
			// magic
			rotationAxis.CrossProduct( &matSpeedVecRotate.vFront );
			// control
			thetaBase = abs(sinh(vecSpeedRotate.DotProduct(&matSpeedVecRotate.vFront)) - 1.175f) / 2.35f + 1.0f;
			theta = thetaBase * rotationMultiplier;
			if ( !near_zero(theta) )
			{
				// rotate
				matSpeedVecRotate = matSpeedVecRotate.Rotate( &rotationAxis, theta );

				// calculate new speed
				float speedReduction = time_diff * (vecSpeed.Length() * (thetaBase - 1.0f));

				// set new speed vector
				matSpeedVecRotate.vFront.Normalize();
				ainfo->m_SpeedVec = matSpeedVecRotate.vFront * ( ainfo->m_SpeedVec.Length() - speedReduction );
			}

			// change animation when we're turning hard & not accelerating
			if (speed > 0.45f
				&& keySpeedState == speed_none
				&& !playerFly_animationDeceleration
				&& ( keyStrafeState == strafe_none || keyStrafeState == strafe_up )
				)
			{
				if ( (GetTickCount() - 500) > playerFly_animationStrafeStateTimer )
				{
					if (playerFly_lastAnimationStates != anim_FALL_skyDive)
					{
						playerFly_lastAnimationStates = anim_FALL_skyDive;
						GTAfunc_PerformAnimation("PARACHUTE", "FALL_skyDive", -1, 1, 1, 0, 0, 0, 1, 0);
					}
					playerFly_animationDeceleration = true;
					playerFly_animationDirectionSpeedDownChanged = false;
				}
				else if ( keyStrafeState == strafe_up )
				{
					if (playerFly_lastAnimationStates != anim_FALL_skyDive)
					{
						playerFly_lastAnimationStates = anim_FALL_skyDive;
						GTAfunc_PerformAnimation("PARACHUTE", "FALL_skyDive", -1, 1, 1, 0, 0, 0, 1, 0);
					}
					playerFly_animationDeceleration = true;
					playerFly_animationDirectionSpeedDownChanged = false;
				}
			}
			else if ( !playerFly_animationDirectionSpeedDownChanged
				&& ( speed < 0.45f )
				)
			{
				if ( keySpeedState == speed_none )
				{
					if (playerFly_lastAnimationStates != anim_Swim_Tread)
					{
						playerFly_lastAnimationStates = anim_Swim_Tread;
						GTAfunc_PerformAnimation("SWIM", "Swim_Tread", -1, 1, 1, 0, 0, 0, 1, 0);
					}
					playerFly_animationDeceleration = false;
				}
				playerFly_animationDirectionSpeedDownChanged = true;
			}

// set the ped rotation target

			// copy speed and normalize, for initial direction
			CVector vecPedRotate = matSpeedVecRotate.vFront; // should use the rotated speed, not original speed
			vecPedRotate.Normalize();

			CMatrix matPedTarget;
			matPedTarget.vFront = matCamera.vFront;
			matPedTarget.vRight = matCamera.vRight + (playerFly_lastPedRotation.vRight * 0.2f);
			matPedTarget.vRight.Normalize();
			matPedTarget.vUp = matCamera.vUp;

			// rotate the ped rotation target to direction of speed
			if (!near_zero(vecSpeed.Length()))
			{
				// rotate target
				rotationAxis = g_vecUpNormal;
				rotationAxis.CrossProduct( &vecPedRotate );
				thetaBase = vecSpeedRotate.DotProduct(&vecPedRotate);
				// drifting
				rotationMultiplier = (time_diff * 69.0f) / ( 18.0f + (vecSpeed.Length() * 1.75f) );
				theta = cos(thetaBase * rotationMultiplier);
				if ( !near_zero(theta) )
				{
					matPedTarget = matPedTarget.Rotate( &rotationAxis, theta );
				}
				// recopy original front
				matPedTarget.vFront = vecPedRotate;

				// rotate the ped rotation target upward during deceleration
				// animation so that the animation is at the correct angle
				if (playerFly_animationDeceleration)
				{
					CVector upStrafeAxis = vecPedRotate;
					upStrafeAxis.CrossProduct(&matPedTarget.vUp);
					rotationMultiplier = (time_diff * 69.0f) / ( 1.0f + (vecSpeed.Length() * 0.25f) );
					thetaBase = -1.5;// * rotationMultiplier; // 1.57 = 90 degrees
					theta = cos(thetaBase * rotationMultiplier);

					// rotate the ped rotation target to direction of speed
					if (!near_zero(vecSpeed.Length()))
					{
						matPedTarget = matPedTarget.Rotate( &upStrafeAxis, theta );
					}
					//upStrafeAxis = upStrafeAxisBuffer;
				}
			}

			// invert right z during strafing
			if ( keyStrafeState == strafe_left
				|| keyStrafeState == strafe_right )
			{
				matPedTarget.vRight.fZ = -matPedTarget.vRight.fZ / 2.0f;
			}

			// normalize everything
			matPedTarget.Normalize(false); // sure, why not

// rotate the ped

			// actual rotation of the ped to smooth movements
			rotationMultiplier = (time_diff * 69.0f) / ( 12.0f + (vecSpeed.Length() * 1.5f) );

			// front camera offset
			rotationAxis = playerFly_lastPedRotation.vFront;
			frontCamOffsetTarget = playerFly_lastPedRotation.vFront;
			frontCamOffsetTarget.Normalize();
			rotationAxis.CrossProduct( &frontCamOffsetTarget );
			thetaBase = playerFly_lastPedRotation.vFront.DotProduct(&frontCamOffsetTarget);
			theta = -cos(thetaBase) * ((time_diff * 69.0f) / 4.5f);
			if ( !near_zero(theta) )
			{
				playerFly_lastPedRotation = playerFly_lastPedRotation.Rotate( &rotationAxis, theta );
				matPedTarget = matPedTarget.Rotate( &rotationAxis, -theta );
			}

			// front
			rotationAxis = playerFly_lastPedRotation.vFront;
			rotationAxis.CrossProduct( &matPedTarget.vFront );
			thetaBase = playerFly_lastPedRotation.vFront.DotProduct(&matPedTarget.vFront);
			theta = -cos(thetaBase) * rotationMultiplier;
			if ( !near_zero(theta) )
			{
				playerFly_lastPedRotation = playerFly_lastPedRotation.Rotate( &rotationAxis, theta );
				matPedTarget = matPedTarget.Rotate( &rotationAxis, theta );
			}

			// right
			rotationAxis = playerFly_lastPedRotation.vRight;
			rotationAxis.CrossProduct( &matPedTarget.vRight );
			thetaBase = playerFly_lastPedRotation.vRight.DotProduct(&matPedTarget.vRight);
			theta = -cos(thetaBase) * (rotationMultiplier * 0.825f);
			if ( !near_zero(theta) )
			{
				playerFly_lastPedRotation = playerFly_lastPedRotation.Rotate( &rotationAxis, theta );
				matPedTarget = matPedTarget.Rotate( &rotationAxis, theta );
			}

			// up
			rotationAxis = playerFly_lastPedRotation.vUp + (g_vecUpNormal / 1.4f);
			rotationAxis.Normalize();
			rotationAxis.CrossProduct( &matPedTarget.vUp );
			thetaBase = playerFly_lastPedRotation.vUp.DotProduct(&matPedTarget.vUp);
			theta = -cos(thetaBase) * (rotationMultiplier / 8.0f);
			if ( !near_zero(theta) )
			{
				playerFly_lastPedRotation = playerFly_lastPedRotation.Rotate( &rotationAxis, theta );
				//matPedTarget = matPedTarget.Rotate( &rotationAxis, theta );
			}

			// normalize everything
			playerFly_lastPedRotation.vFront.Normalize();
			playerFly_lastPedRotation.vRight.Normalize();
			playerFly_lastPedRotation.vUp.Normalize();

			// zero near zero
			playerFly_lastPedRotation.vFront.ZeroNearZero();
			playerFly_lastPedRotation.vRight.ZeroNearZero();
			playerFly_lastPedRotation.vUp.ZeroNearZero();

			// set the position
			playerFly_lastPedRotation.vPos = pPedSelfSA->Placeable.matrix->vPos;

			// set player matrix
			pPedSelf->SetMatrix(&playerFly_lastPedRotation);

// set the camera (our CPed gravity gets ignored while flying)

			// we should be setting it like this
			//CVector smoothedGrav = -playerFly_lastPedRotation.vUp + (g_vecUpNormal * 2.0f);
			//smoothedGrav.Normalize();
			//pPedSelf->SetGravity( &smoothedGrav );
			// -nf

			// but the function is hacked to hell to make it work, so since we're the only
			// thing using it so far, we'll just do this, and fudge the camera in the hook
			// -nf
			pPedSelf->SetGravity( &-playerFly_lastPedRotation.vUp );

			// actually... the camera is doing quite a lot now which is flying specific, with some
			// logic to run when actually flying, so...  just doing literal set gravity is appropriate for now.
			// -nf

		}
	}
	else if ( cheat_state->actor.fly_enabled )
	{
		// set fly disabled
		cheat_state->actor.fly_enabled = false;
		if (cheat_state->actor.fly_active)
		{
			cheat_state->actor.fly_active = false;
			// set gravity down
			pPedSelf->SetGravity( &-g_vecUpNormal );
			// remove up speed hard limiter patch
			if (patch_RemoveFlyUpSpeedLimit.installed)
			{
				patcher_remove(&patch_RemoveFlyUpSpeedLimit);
			}
			// remove fly soft limiters patch
			if (patch_RemoveFlyWindSpeedLimit.installed)
			{
				patcher_remove(&patch_RemoveFlyWindSpeedLimit);
			}
			// copy camera rotation to player
			ainfo->fCurrentRotation = -pGame->GetCamera()->GetCameraRotation();
			ainfo->fTargetRotation = ainfo->fCurrentRotation;
			// stop animation
			playerFly_lastAnimationStates = SHP_Jump_Land;
			GTAfunc_PerformAnimation("SHOP", "SHP_Jump_Land ", -1, 0, 1, 0, 0, 0, 0, 0);
		}
		playerFly_lastKeySpeedState = speed_none;
	}
}