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; }
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; }
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 ); } }
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 ); }
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); } } }
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(); } } }
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; } }