void CGibFX::CreateBloodSpray() { CSFXMgr* psfxMgr = g_pGameClientShell->GetSFXMgr(); if (!psfxMgr) return; BSCREATESTRUCT sc; VEC_COPY(sc.vPos, m_vPos); sc.vPos.y += 30.0f; VEC_SET(sc.vVel, 0.0f, -20.0f, 0.0f); VEC_SET(sc.vInitialScale, GetRandom(2.0f, 4.0f), GetRandom(2.0f, 4.0f), 1.0f); VEC_SET(sc.vFinalScale, GetRandom(0.5f, 0.8f), GetRandom(0.5f, 0.8f), 1.0f); sc.dwFlags = FLAG_VISIBLE | FLAG_SPRITEBIAS | FLAG_NOLIGHT; sc.fLifeTime = 0.5f; sc.fInitialAlpha = 1.0f; sc.fFinalAlpha = 0.0f; sc.nType = OT_SPRITE; char* pBloodFiles[] = { "Sprites\\BloodSplat1.spr", "Sprites\\BloodSplat2.spr", "Sprites\\BloodSplat3.spr", "Sprites\\BloodSplat4.spr" }; sc.pFilename = pBloodFiles[GetRandom(0,3)]; CSpecialFX* pFX = psfxMgr->CreateSFX(SFX_SCALE_ID, &sc); if (pFX) pFX->Update(); }
void CWeaponFX::CreateMark(LTVector vPos, LTVector vNorm, LTRotation rRot, SurfaceType eType) { IMPACTFX* pImpactFX = m_pAmmo->pImpactFX; if (IsLiquid(m_eCode)) { pImpactFX = m_pAmmo->pUWImpactFX; } if (!pImpactFX) return; CSFXMgr* psfxMgr = g_pGameClientShell->GetSFXMgr(); if (!psfxMgr) return; MARKCREATESTRUCT mark; mark.m_vPos = vPos; mark.m_Rotation = rRot; // Randomly rotate the bullet hole... g_pLTClient->RotateAroundAxis(&mark.m_Rotation, &vNorm, GetRandom(0.0f, MATH_CIRCLE)); mark.m_fScale = pImpactFX->fMarkScale; mark.nAmmoId = m_nAmmoId; mark.nSurfaceType = eType; psfxMgr->CreateSFX(SFX_MARK_ID, &mark); }
// ----------------------------------------------------------------------- // // // ROUTINE: CAutoTargetMgr::AddMagnets() // // PURPOSE: Add any aim magnets in our cone to the array // // ----------------------------------------------------------------------- // void CAutoTargetMgr::AddMagnets() { CSFXMgr* psfxMgr = g_pGameClientShell->GetSFXMgr(); //step through the chars CSpecialFXList* const pMagnetList = psfxMgr->GetFXList(SFX_AIMMAGNET_ID); int nNumSFX = pMagnetList->GetSize(); for (int nMag=0; nMag < nNumSFX; nMag++) { CAimMagnetFX* pMag = (CAimMagnetFX*)(*pMagnetList)[nMag]; if (pMag) { uint32 dwFlags; g_pCommonLT->GetObjectFlags(pMag->GetServerObj(), OFT_Flags, dwFlags); if (!(dwFlags & FLAG_VISIBLE)) continue; //filter out anyone outside the cone LTVector vTargetPos; g_pLTClient->GetObjectPos(pMag->GetTarget(), &vTargetPos); if (IsPointInCone( vTargetPos ) && m_nNodeCount < MAX_AUTOTARGET_NODES) { m_NodeArray[m_nNodeCount].vPos = vTargetPos; m_NodeArray[m_nNodeCount].hChar = pMag->GetTarget(); m_nNodeCount++; } } } }
void CWeaponFX::CreateBulletTrail(LTVector *pvStartPos) { CSFXMgr* psfxMgr = g_pGameClientShell->GetSFXMgr(); if (!psfxMgr || !pvStartPos) return; LTVector vColor1, vColor2; vColor1.Init(200.0f, 200.0f, 200.0f); vColor2.Init(255.0f, 255.0f, 255.0f); BTCREATESTRUCT bt; bt.vStartPos = *pvStartPos; bt.vDir = m_vDir; bt.vColor1 = vColor1; bt.vColor2 = vColor2; bt.fLifeTime = 0.5f; bt.fFadeTime = 0.3f; bt.fRadius = 400.0f; bt.fGravity = 0.0f; bt.fNumParticles = (m_nDetailLevel == RS_MED) ? 15.0f : 30.0f; CSpecialFX* pFX = psfxMgr->CreateSFX(SFX_BULLETTRAIL_ID, &bt); // Let each bullet trail do its initial update... if (pFX) pFX->Update(); }
void CDeathFX::CreateVehicleDeathFX() { CSFXMgr* psfxMgr = g_pGameClientShell->GetSFXMgr(); if (!psfxMgr) return; GIBCREATESTRUCT gib; m_pClientDE->AlignRotation(&(gib.rRot), &m_vDir, LTNULL); LTFLOAT fDamage = VEC_MAG(m_vDir); VEC_COPY(gib.vPos, m_vPos); VEC_SET(gib.vMinVel, 50.0f, 100.0f, 50.0f); VEC_MULSCALAR(gib.vMinVel, gib.vMinVel, fDamage); VEC_SET(gib.vMaxVel, 100.0f, 200.0f, 100.0f); VEC_MULSCALAR(gib.vMaxVel, gib.vMaxVel, fDamage); gib.fLifeTime = 20.0f; gib.fFadeTime = 7.0f; gib.nGibFlags = 0; gib.bRotate = LTTRUE; gib.eModelId = m_eModelId; gib.eModelStyle = m_eModelStyle; gib.nCode = m_eCode; gib.bSubGibs = LTTRUE; SetupGibTypes(gib); psfxMgr->CreateSFX(SFX_GIB_ID, &gib); }
void CWeaponFX::CreateTracer() { if (!m_pAmmo || !m_pAmmo->pTracerFX) return; CSFXMgr* psfxMgr = g_pGameClientShell->GetSFXMgr(); if (!psfxMgr) return; if (m_nDetailLevel != RS_HIGH && GetRandom(1, 2) == 1) return; // Create tracer... if (m_fFireDistance > 100.0f) { TRCREATESTRUCT tracer; // Make tracer start in front of gun a little ways... tracer.vStartPos = m_vFirePos; // + (m_vDir * 25.0f); tracer.vEndPos = m_vPos; tracer.pTracerFX = m_pAmmo->pTracerFX; CSpecialFX* pFX = psfxMgr->CreateSFX(SFX_TRACER_ID, &tracer); if (pFX) pFX->Update(); } }
void CGibFX::CreateLingeringSmoke(int nIndex) { CSFXMgr* psfxMgr = g_pGameClientShell->GetSFXMgr(); if (!psfxMgr) return; CGameSettings* pSettings = g_pInterfaceMgr->GetSettings(); if (!pSettings) return; uint8 nDetailLevel = pSettings->SpecialFXSetting(); if (nDetailLevel == RS_LOW) return; SMCREATESTRUCT sm; char* pTexture = "Sprites\\SmokeTest.spr"; VEC_SET(sm.vColor1, 100.0f, 100.0f, 100.0f); VEC_SET(sm.vColor2, 125.0f, 125.0f, 125.0f); VEC_SET(sm.vMinDriftVel, -10.0f, 25.0f, -10.0f); VEC_SET(sm.vMaxDriftVel, 10.0f, 50.0f, 10.0f); LTFLOAT fVolumeRadius = 10.0f; LTFLOAT fLifeTime = GetRandom(m_fLifeTime * 0.75f, m_fLifeTime); LTFLOAT fRadius = 1500; LTFLOAT fParticleCreateDelta = 0.1f; LTFLOAT fMinParticleLife = 1.0f; LTFLOAT fMaxParticleLife = 5.0f; uint8 nNumParticles = 3; LTBOOL bIgnoreWind = LTFALSE; if (IsLiquid(m_eCode)) { GetLiquidColorRange(m_eCode, &sm.vColor1, &sm.vColor2); pTexture = DEFAULT_BUBBLE_TEXTURE; fRadius = 750.0f; bIgnoreWind = LTTRUE; fMinParticleLife = 1.0f; fMaxParticleLife = 1.5f; } sm.vPos = m_Emitters[nIndex].m_vPos; sm.hServerObj = m_hGib[nIndex]; sm.fVolumeRadius = fVolumeRadius; sm.fLifeTime = fLifeTime; sm.fRadius = fRadius; sm.fParticleCreateDelta = fParticleCreateDelta; sm.fMinParticleLife = fMinParticleLife; sm.fMaxParticleLife = fMaxParticleLife; sm.nNumParticles = nNumParticles; sm.bIgnoreWind = bIgnoreWind; sm.hstrTexture = m_pClientDE->CreateString(pTexture); psfxMgr->CreateSFX(SFX_SMOKE_ID, &sm); m_pClientDE->FreeString(sm.hstrTexture); }
LTBOOL CParticleTrailFX::Update() { CSFXMgr* psfxMgr = g_pRiotClientShell->GetSFXMgr(); if (!psfxMgr || !m_pClientDE || !m_hServerObject) return LTFALSE; LTFLOAT fTime = m_pClientDE->GetTime(); // Check to see if we should go away... if (m_bWantRemove) { return LTFALSE; } // See if it is time to create a new trail segment... if ((m_fStartTime < 0) || (fTime > m_fStartTime + m_fSegmentTime)) { PTSCREATESTRUCT pts; pts.hServerObj = m_hServerObject; VEC_COPY(pts.vColor1, m_vColor1); VEC_COPY(pts.vColor2, m_vColor2); VEC_COPY(pts.vDriftOffset, m_vDriftOffset); pts.nType = m_nType; pts.bSmall = m_bSmall; pts.fLifeTime = m_fLifeTime; pts.fFadeTime = m_fFadeTime; pts.fOffsetTime = m_fOffsetTime; pts.fRadius = 2000.0f; pts.fGravity = 0.0f; pts.nNumPerPuff = m_nNumPerPuff; if (m_nType & PT_BLOOD) { pts.fRadius = 600.0f; } else if (m_nType & PT_GIBSMOKE) { pts.fRadius = 1250.0f; } CSpecialFX* pFX = psfxMgr->CreateSFX(SFX_PARTICLETRAILSEG_ID, &pts); // Let each Particle segment do its initial update... if (pFX) pFX->Update(); m_fStartTime = fTime; } return LTTRUE; }
DBOOL CSmokeTrailFX::Update() { CBloodClientShell *pShell = (CBloodClientShell*)g_pClientDE->GetClientShell(); CSFXMgr* psfxMgr = pShell->GetSFXMgr(); if (!psfxMgr || !m_pClientDE || !m_hServerObject) return DFALSE; DFLOAT fTime = m_pClientDE->GetTime(); // Check to see if we should go away... if (m_bWantRemove) { return DFALSE; } // See if it is time to create a new trail segment... if ((m_fStartTime < 0) || (fTime > m_fStartTime + m_fSegmentTime)) { STSCREATESTRUCT sts; sts.hServerObj = m_hServerObject; VEC_COPY(sts.vVel, m_vVel); VEC_COPY(sts.vColor1, m_vColor1); VEC_COPY(sts.vColor2, m_vColor2); sts.bSmall = m_bSmall; sts.fLifeTime = m_fLifeTime; sts.fFadeTime = m_fFadeTime; sts.fOffsetTime = m_fOffsetTime; sts.fRadius = 1000.0f; sts.fGravity = 15.0f; sts.nNumPerPuff = m_nNumPerPuff; if(VEC_MAG(sts.vVel) < 1.0f) { sts.fGravity = 25.0f; sts.fOffsetTime = 0.1f; sts.fRadius = 500.0f; sts.nNumPerPuff = 1; sts.fLifeTime = 1.0f; } CSpecialFX* pFX = psfxMgr->CreateSFX(SFX_SMOKETRAILSEG_ID, &sts, DFALSE, this); // Let each smoke segment do its initial update... if (pFX) pFX->Update(); m_fStartTime = fTime; } return DTRUE; }
void CWeaponFX::CreateShell() { CSFXMgr* psfxMgr = g_pGameClientShell->GetSFXMgr(); if (!psfxMgr) return; SHELLCREATESTRUCT sc; sc.rRot = m_rDirRot; sc.vStartPos = m_vFirePos; sc.nWeaponId = m_nWeaponId; sc.nAmmoId = m_nAmmoId; sc.b3rdPerson = LTFALSE; // See if this is our local client who fired, and if so are we in 3rd person... if (m_nLocalId == m_nShooterId) { sc.b3rdPerson = !g_pGameClientShell->IsFirstPerson(); } else { sc.b3rdPerson = LTTRUE; } // Adjust the shell position based on the hand-held breach offset... if (sc.b3rdPerson) { sc.vStartPos += (m_vDir * m_pWeapon->fHHBreachOffset); } else // Get the shell eject pos... { sc.vStartPos = g_pGameClientShell->GetWeaponModel()->GetShellEjectPos(sc.vStartPos); // Add on the player's velocity... HOBJECT hObj = g_pGameClientShell->GetMoveMgr()->GetObject(); if (hObj) { g_pLTClient->Physics()->GetVelocity(hObj, &sc.vStartVel); } //sc.dwFlags = FLAG_REALLYCLOSE; } // Only create every other shell if medium detail set... // if (m_nDetailLevel == RS_MED && (++s_nNumShells % 2 == 0)) return; psfxMgr->CreateSFX(SFX_SHELLCASING_ID, &sc); }
void CGibFX::CreateMiniBloodExplosion(int nIndex) { // Add a mini blood explosion... CSFXMgr* psfxMgr = g_pGameClientShell->GetSFXMgr(); if (!psfxMgr) return; CGameSettings* pSettings = g_pInterfaceMgr->GetSettings(); if (!pSettings) return; uint8 nDetailLevel = pSettings->SpecialFXSetting(); if (nDetailLevel == RS_LOW) return; char* szBlood[2] = { "SpecialFX\\ParticleTextures\\Blood_1.dtx", "SpecialFX\\ParticleTextures\\Blood_2.dtx" }; PARTICLESHOWERCREATESTRUCT ps; ps.vPos = m_Emitters[nIndex].m_vPos; ps.vPos.y += 30.0f; ps.vDir.Init(0, 100, 0); VEC_SET(ps.vColor1, 200.0f, 200.0f, 200.0f); VEC_SET(ps.vColor2, 255.0f, 255.0f, 255.0f); ps.pTexture = szBlood[GetRandom(0,1)];; ps.nParticles = 50; ps.fDuration = 1.0f; ps.fEmissionRadius = 0.3f; ps.fRadius = 800.0f; ps.fGravity = PSFX_DEFAULT_GRAVITY; if (IsLiquid(m_eCode)) { ps.vDir *= 3.0f; ps.fEmissionRadius = 0.2f; ps.fRadius = 700.0f; } psfxMgr->CreateSFX(SFX_PARTICLESHOWER_ID, &ps); // Play appropriate sound... char* pSound = GetGibDieSound(); if (pSound) { g_pClientSoundMgr->PlaySoundFromPos(ps.vPos, pSound, 300.0f, SOUNDPRIORITY_MISC_LOW); } }
void CWeaponFX::CreateMuzzleLight() { // Check to see if we have the silencer... if (m_wFireFX & WFX_SILENCED) return; if (m_nLocalId != m_nShooterId || !g_pGameClientShell->IsFirstPerson()) { MUZZLEFLASHCREATESTRUCT mf; mf.pWeapon = m_pWeapon; mf.hParent = m_hFiredFrom; mf.vPos = m_vFirePos; mf.rRot = m_rDirRot; CSFXMgr* psfxMgr = g_pGameClientShell->GetSFXMgr(); if (!psfxMgr) return; psfxMgr->CreateSFX(SFX_MUZZLEFLASH_ID, &mf); } }
void CWeaponFX::CreateMuzzleFX() { CSFXMgr* psfxMgr = g_pGameClientShell->GetSFXMgr(); if (!psfxMgr) return; char* pTexture = "SFX\\Impact\\Spr\\Smoke.spr"; if (IsLiquid(m_eFirePosCode)) { pTexture = DEFAULT_BUBBLE_TEXTURE; } PARTICLESHOWERCREATESTRUCT sp; sp.vPos = m_vFirePos; sp.vDir = m_vSurfaceNormal * 10.0f; sp.pTexture = pTexture; sp.nParticles = 1; sp.fRadius = 400.0f; sp.fDuration = 1.0f; sp.fEmissionRadius = 0.05f; sp.fRadius = 800.0f; sp.fGravity = 0.0f; sp.vColor1.Init(100.0f, 100.0f, 100.0f); sp.vColor2.Init(125.0f, 125.0f, 125.0f); if (IsLiquid(m_eFirePosCode)) { GetLiquidColorRange(m_eFirePosCode, &sp.vColor1, &sp.vColor2); sp.fRadius = 600.0f; sp.fGravity = 50.0f; } psfxMgr->CreateSFX(SFX_PARTICLESHOWER_ID, &sp); }
DBOOL CBloodTrailFX::Update() { CBloodClientShell *pShell = (CBloodClientShell*)g_pClientDE->GetClientShell(); CSFXMgr* psfxMgr = pShell->GetSFXMgr(); if (!psfxMgr || !m_pClientDE || !m_hServerObject) return DFALSE; DFLOAT fTime = m_pClientDE->GetTime(); // Check to see if we should go away... if (m_bWantRemove || (m_hServerObject == DNULL)) { return DFALSE; } // See if it is time to create a new trail segment... if ((m_fStartTime < 0) || (fTime > m_fStartTime + m_fSegmentTime)) { BTSCREATESTRUCT bts; bts.hServerObj = m_hObject; VEC_COPY(bts.vColor1, m_vColor); bts.fLifeTime = m_fLifeTime; bts.fOffsetTime = m_fOffsetTime; bts.fRadius = 200.0f; bts.nNumPerPuff = m_nNumPerPuff; CSpecialFX* pFX = psfxMgr->CreateSFX(SFX_BLOODTRAILSEG_ID, &bts, DFALSE, this); if (pFX) pFX->Update(); m_fStartTime = fTime; } return DTRUE; }
// ----------------------------------------------------------------------- // // // ROUTINE: CAutoTargetMgr::GenerateCharArray() // // PURPOSE: Fill array with list of chars sorted by distance // // ----------------------------------------------------------------------- // void CAutoTargetMgr::GenerateCharArray() { //clear our target array m_Targets.resize(0); CSFXMgr* psfxMgr = g_pGameClientShell->GetSFXMgr(); //step through the chars CSpecialFXList* const pCharList = psfxMgr->GetFXList(SFX_CHARACTER_ID); int nNumSFX = pCharList->GetSize(); for (int nChar=0; nChar < nNumSFX; nChar++) { CCharacterFX* pChar = (CCharacterFX*)(*pCharList)[nChar]; if (pChar) { if (pChar->m_cs.bIsPlayer) { //filter out local player HLOCALOBJ hPlayerObj = g_pLTClient->GetClientObject(); if (hPlayerObj == pChar->GetServerObj()) continue; if(pChar->IsPlayerDead()) continue; //if this is a team game filter out our teammates if (GameModeMgr::Instance( ).m_grbUseTeams ) { // Get the client information of the body and us. uint32 nId = pChar->m_cs.nClientID; CClientInfoMgr* pCIMgr = g_pInterfaceMgr->GetClientInfoMgr(); CLIENT_INFO* pCI = pCIMgr->GetClientByID(nId); CLIENT_INFO *pLocalCI = g_pInterfaceMgr->GetClientInfoMgr()->GetLocalClient(); // Only allow us to auto-target people on the other team. if( pCI && pLocalCI ) { if (pCI->nTeamID == pLocalCI->nTeamID) continue; } } } else { // Check alignment of non-players if(pChar->m_cs.eCrosshairPlayerStance != kCharStance_Hate) continue; } //filter out anyone outside the cone LTVector vTargetPos; g_pLTClient->GetObjectPos(pChar->GetServerObj(), &vTargetPos); LTVector vOffset(0.0f,32.0f,0.0f); // we check both upper and lower parts of the body and if either is in the cone, we're good if (IsPointInCone( vTargetPos - vOffset) || IsPointInCone( vTargetPos + vOffset) ) { // we only care about the n closest characters, so... // if the new one farther away than the n-th one, drop it, // otherwise drop the n-th one and insert the new one //step through the chars we already know about... CharFXArray::iterator iter = m_Targets.begin(); bool bInserted = false; while (iter != m_Targets.end() && !bInserted) { //figure out how far away this one is CCharacterFX* pTestChar = (CCharacterFX*)(*iter); LTVector vTestPos; g_pLTClient->GetObjectPos(pTestChar->GetServerObj(), &vTestPos); float fTestDistSqr = m_vFirePos.DistSqr(vTestPos); //if this char is farther away than the one we're inserting if (fTestDistSqr > m_fRangeSqr) { //if our list is full, pop off the last one... if (m_Targets.size() >= MAX_AUTOTARGET_CHARACTERS) m_Targets.pop_back(); m_Targets.insert(iter,pChar); bInserted = true; } iter++; } //if we haven't inseted it yet, and we have room, add it to the back if (!bInserted && m_Targets.size() < MAX_AUTOTARGET_CHARACTERS) m_Targets.push_back(pChar); } } } }
LTBOOL CFireFX::Update() { CSFXMgr* psfxMgr = g_pGameClientShell->GetSFXMgr(); if (!psfxMgr || !m_pClientDE || !m_hServerObject) return LTFALSE; LTFLOAT fTime = m_pClientDE->GetTime(); // Check to see if we should go away... if (m_bWantRemove) { return LTFALSE; } // Update FX... if (m_cs.bCreateSmoke) { m_Smoke1.Update(); } if (m_cs.bCreateLight) { m_Light.Update(); } m_Fire1.Update(); m_Fire2.Update(); // Hide/show the fire if necessary... if (m_hServerObject) { uint32 dwUserFlags; m_pClientDE->GetObjectUserFlags(m_hServerObject, &dwUserFlags); if (!(dwUserFlags & USRFLG_VISIBLE)) { if (m_hSound) { g_pLTClient->KillSound(m_hSound); m_hSound = LTNULL; } return LTTRUE; } else { if (m_cs.bCreateSound && !m_hSound) { CString str = g_pClientButeMgr->GetSpecialFXAttributeString("FireSnd"); m_hSound = g_pClientSoundMgr->PlaySoundFromPos(m_cs.vPos, (char*)(LPCSTR)str, m_cs.fSoundRadius, SOUNDPRIORITY_MISC_MEDIUM, PLAYSOUND_GETHANDLE | PLAYSOUND_LOOP); } } } // Create the random spark particles... if (m_cs.bCreateSparks && GetRandom(1, 10) == 1) { CSFXMgr* psfxMgr = g_pGameClientShell->GetSFXMgr(); if (!psfxMgr) return LTFALSE; RANDOMSPARKSCREATESTRUCT sparks; sparks.hServerObj = m_hServerObject; LTFLOAT fVel = m_fSizeAdjust * GetRandom(50.0f, 70.0f); fVel = (fVel < 30.0f ? 30.0f : (fVel > 100.0f ? 100.0f : fVel)); LTVector vDir(0.0, 1.0, 0.0); sparks.vMinVelAdjust.Init(1, 3, 1); sparks.vMaxVelAdjust.Init(1, 6, 1); sparks.vDir = vDir * fVel; sparks.nSparks = GetRandom(1, 5); sparks.fDuration = m_fSizeAdjust * GetRandom(1.0f, 2.0f); sparks.bRelToCameraPos = LTTRUE; sparks.fInnerCamRadius = FFX_INNER_CAM_RADIUS; sparks.fOuterCamRadius = FFX_INNER_CAM_RADIUS + (FFX_CAM_FALLOFF_RANGE * m_fSizeAdjust); sparks.fRadius = 300.0f * m_fSizeAdjust; sparks.fRadius = sparks.fRadius < 100.0f ? 100.0f : (sparks.fRadius > 500.0f ? 500.0f : sparks.fRadius); psfxMgr->CreateSFX(SFX_RANDOMSPARKS_ID, &sparks); } return LTTRUE; }
void CGibFX::HandleBounce(int nIndex) { if (nIndex < 0 || nIndex >= m_nNumGibs) return; // Play a bounce sound if the gib isn't in liquid... if (!(m_Emitters[nIndex].m_dwPhysicsFlags & MO_LIQUID) && (m_hGib[nIndex])) { if (m_bPlayBounceSound && GetRandom(1, 4) != 1) { char* pSound = GetBounceSound(); // Play appropriate sound... if (pSound) { g_pClientSoundMgr->PlaySoundFromPos(m_Emitters[nIndex].m_vPos, pSound, 1000.0f, SOUNDPRIORITY_MISC_LOW); } } } // See if we're resting... m_BounceCount[nIndex]--; if (m_BounceCount[nIndex] <= 0) { m_Emitters[nIndex].m_dwPhysicsFlags |= MO_RESTING; if (m_bSubGibs) HandleDoneBouncing(nIndex); } // Add a blood splat... if (m_bBloodSplats) { // Don't add blood splats on the sky... uint32 dwTextureFlags; m_pClientDE->GetPolyTextureFlags(m_info.m_hPoly, &dwTextureFlags); SurfaceType eType = (SurfaceType)dwTextureFlags; if (eType == ST_SKY) return; CSFXMgr* psfxMgr = g_pGameClientShell->GetSFXMgr(); if (!psfxMgr) return; BSCREATESTRUCT sc; m_pClientDE->AlignRotation(&(sc.rRot), &(m_info.m_Plane.m_Normal), LTNULL ); LTVector vTemp; VEC_MULSCALAR(vTemp, m_info.m_Plane.m_Normal, 2.0f); VEC_ADD(sc.vPos, m_info.m_Point, vTemp); // Off the wall/floor a bit VEC_SET(sc.vVel, 0.0f, 0.0f, 0.0f); VEC_SET(sc.vInitialScale, GetRandom(0.3f, 0.5f), GetRandom(0.3f, 0.5f), 1.0f); VEC_SET(sc.vFinalScale, GetRandom(0.8f, 1.0f), GetRandom(0.8f, 1.0f), 1.0f); sc.dwFlags = FLAG_VISIBLE | FLAG_ROTATEABLESPRITE | FLAG_NOLIGHT; sc.fLifeTime = m_fLifeTime + 10.0f; sc.fInitialAlpha = 1.0f; sc.fFinalAlpha = 0.0f; sc.nType = OT_SPRITE; char* pBloodFiles[] = { "Sprites\\BloodSplat1.spr", "Sprites\\BloodSplat2.spr", "Sprites\\BloodSplat3.spr", "Sprites\\BloodSplat4.spr" }; sc.pFilename = pBloodFiles[GetRandom(0,3)]; CSpecialFX* pFX = psfxMgr->CreateSFX(SFX_SCALE_ID, &sc); if (pFX) pFX->Update(); } }
void CWeaponFX::CreateBloodSplatFX() { CGameSettings* pSettings = g_pInterfaceMgr->GetSettings(); if (!pSettings || !pSettings->Gore()) return; CSFXMgr* psfxMgr = g_pGameClientShell->GetSFXMgr(); if (!psfxMgr) return; CSpecialFX* pFX = LTNULL; LTFLOAT fRange = g_vtBloodSplatsRange.GetFloat(); // See if we should make some blood splats... ClientIntersectQuery iQuery; IntersectInfo iInfo; iQuery.m_From = m_vPos; LTVector vDir = m_vDir; // Create some blood splats... int nNumSplats = GetRandom((int)g_vtBloodSplatsMinNum.GetFloat(), (int)g_vtBloodSplatsMaxNum.GetFloat()); LTVector vU, vR, vF; g_pLTClient->GetRotationVectors(&m_rDirRot, &vU, &vR, &vF); for (int i=0; i < nNumSplats; i++) { LTVector vDir = m_vDir; // Perturb direction after first splat... if (i > 0) { float fPerturb = g_vtBloodSplatsPerturb.GetFloat(); float fRPerturb = (GetRandom(-fPerturb, fPerturb))/1000.0f; float fUPerturb = (GetRandom(-fPerturb, fPerturb))/1000.0f; vDir += (vR * fRPerturb); vDir += (vU * fUPerturb); } iQuery.m_To = vDir * fRange; iQuery.m_To += m_vPos; iQuery.m_Flags = IGNORE_NONSOLID | INTERSECT_HPOLY; if (g_pLTClient->IntersectSegment(&iQuery, &iInfo) && IsMainWorld(iInfo.m_hObject)) { SurfaceType eType = GetSurfaceType(iInfo); if (eType == ST_SKY || eType == ST_INVISIBLE) { return; // Don't leave blood on the sky } LTBOOL bBigBlood = (LTBOOL)GetConsoleInt("BigBlood", 0); // Create a blood splat... BSCREATESTRUCT sc; g_pLTClient->AlignRotation(&(sc.rRot), &(iInfo.m_Plane.m_Normal), LTNULL); // Randomly rotate the blood splat g_pLTClient->RotateAroundAxis(&(sc.rRot), &(iInfo.m_Plane.m_Normal), GetRandom(0.0f, MATH_CIRCLE)); LTVector vTemp = vDir * -2.0f; sc.vPos = iInfo.m_Point + vTemp; // Off the wall a bit sc.vVel.Init(0.0f, 0.0f, 0.0f); sc.vInitialScale.Init(1.0f, 1.0f, 1.0f); sc.vInitialScale.x = GetRandom(g_vtBloodSplatsMinScale.GetFloat(), g_vtBloodSplatsMaxScale.GetFloat()); if (bBigBlood) sc.vInitialScale.x *= g_vtBigBloodSizeScale.GetFloat(); sc.vInitialScale.y = sc.vInitialScale.x; sc.vFinalScale = sc.vInitialScale; sc.dwFlags = FLAG_VISIBLE | FLAG_ROTATEABLESPRITE | FLAG_NOLIGHT; sc.fLifeTime = GetRandom(g_vtBloodSplatsMinLifetime.GetFloat(), g_vtBloodSplatsMaxLifetime.GetFloat()); if (bBigBlood) sc.fLifeTime *= g_vtBigBloodLifeScale.GetFloat(); sc.fInitialAlpha = 1.0f; sc.fFinalAlpha = 0.0f; sc.nType = OT_SPRITE; sc.bMultiply = LTTRUE; char* pBloodFiles[] = { "Sfx\\Test\\Spr\\BloodL1.spr", "Sfx\\Test\\Spr\\BloodL2.spr", "Sfx\\Test\\Spr\\BloodL3.spr", "Sfx\\Test\\Spr\\BloodL4.spr" }; sc.pFilename = pBloodFiles[GetRandom(0,3)]; pFX = psfxMgr->CreateSFX(SFX_SCALE_ID, &sc); if (pFX) pFX->Update(); } else if (i==0) { // Didn't hit anything straight back, do don't bother to // do anymore... return; } } }
void CNodeController::HandleNodeConrolLipSync(HSTRING hSound, LTFLOAT fRadius) { ModelNode eModelNode = g_pModelButeMgr->GetSkeletonNode(m_pCharacterFX->GetModelSkeleton(), "LowerJaw"); // See if we are already controlling the jaw node int iCtrl = FindNodeControl(eModelNode, eControlLipSync); char szSound[128]; strcpy(szSound, g_pLTClient->GetStringData(hSound)); g_pLTClient->FreeString(hSound); // Check to make sure all the info is ok... if((eModelNode == eModelNodeInvalid) || fRadius <= 0.0f) { if(iCtrl > -1) { if(m_aNodeControls[iCtrl].hLipSyncSound) { g_pLTClient->KillSound(m_aNodeControls[iCtrl].hLipSyncSound); m_aNodeControls[iCtrl].hLipSyncSound = LTNULL; if (m_aNodeControls[iCtrl].bShowingSubtitles) { g_pInterfaceMgr->ClearSubtitle(); } } m_aNodeControls[iCtrl].bValid = LTFALSE; } return; } // Add the node control structure... int iNodeControl = (iCtrl > -1) ? iCtrl : AddNodeControl(); _ASSERT(iNodeControl >= 0); if ( iNodeControl < 0 ) return; if(m_aNodeControls[iNodeControl].hLipSyncSound) { g_pLTClient->KillSound(m_aNodeControls[iNodeControl].hLipSyncSound); m_aNodeControls[iNodeControl].hLipSyncSound = LTNULL; if (m_aNodeControls[iNodeControl].bShowingSubtitles) { g_pInterfaceMgr->ClearSubtitle(); } } m_aNodeControls[iNodeControl].bValid = LTTRUE; m_aNodeControls[iNodeControl].eControl = eControlLipSync; m_aNodeControls[iNodeControl].eModelNode = eModelNode; m_aNodeControls[iNodeControl].pSixteenBitBuffer = LTNULL; m_aNodeControls[iNodeControl].pEightBitBuffer = LTNULL; LTBOOL bSubtitles = LTFALSE; m_aNodeControls[iNodeControl].hLipSyncSound = m_pCharacterFX->PlayLipSyncSound(szSound, fRadius, bSubtitles); m_aNodeControls[iNodeControl].bShowingSubtitles = bSubtitles; // Increment the number of controllers for this node... m_aNodes[eModelNode].cControllers++; // PLH DEBUG // Show graph over character. #ifdef GRAPH_LIPSYNC_SOUND GCREATESTRUCT graph_init; graph_init.hServerObj = m_pCharacterFX->GetServerObj(); graph_init.m_vOffsetPos = LTVector(0.0f,70.0f,0.0f); graph_init.m_fWidth = 60.0f; graph_init.m_fHeight = 60.0f; graph_init.m_bIgnoreX = LTTRUE; graph_init.m_UpdateGraphCallback = make_callback2<LTBOOL,GraphFXPoint * *, uint32 *>(g_GraphPoints,GraphPoints::GetData); CSFXMgr* psfxMgr = g_pGameClientShell->GetSFXMgr(); if (!psfxMgr) return; psfxMgr->CreateSFX(SFX_GRAPH_ID, &graph_init); #endif }
DBOOL CMarkSFX::CreateObject(CClientDE *pClientDE) { if (!CSpecialFX::CreateObject(pClientDE)) return DFALSE; CSFXMgr* psfxMgr = g_pBloodClientShell->GetSFXMgr(); if (!psfxMgr) return DFALSE; // Before we create a new buillet hole see if there is already another // bullet hole close by that we could use instead... CSpecialFXList* pList = psfxMgr->GetBulletHoleFXList(); if (!pList) return DFALSE; int nNumBulletHoles = pList->GetSize(); HOBJECT hMoveObj = DNULL; HOBJECT hObj = DNULL; DFLOAT fClosestMarkDist = REGION_DIAMETER; DBYTE nNumInRegion = 0; DVector vPos; for (int i=0; i < nNumBulletHoles; i++) { if ((*pList)[i]) { hObj = (*pList)[i]->GetObject(); if (hObj) { pClientDE->GetObjectPos(hObj, &vPos); DFLOAT fDist = VEC_DISTSQR(vPos, m_Pos); if (fDist < REGION_DIAMETER) { if (fDist < fClosestMarkDist) { fClosestMarkDist = fDist; hMoveObj = hObj; } if (++nNumInRegion > MAX_MARKS_IN_REGION) { // Just move this bullet-hole to the correct pos, and // remove thyself... pClientDE->SetObjectPos(hMoveObj, &m_Pos); return DFALSE; } } } } } // Setup the mark... ObjectCreateStruct createStruct; INIT_OBJECTCREATESTRUCT(createStruct); createStruct.m_ObjectType = OT_SPRITE; _mbscpy((unsigned char*)createStruct.m_Filename, (const unsigned char*)m_pClientDE->GetStringData( m_hstrSprite )); createStruct.m_Flags = FLAG_VISIBLE | FLAG_ROTATEABLESPRITE; VEC_COPY(createStruct.m_Pos, m_Pos); ROT_COPY( createStruct.m_Rotation, m_Rotation ); m_hObject = pClientDE->CreateObject(&createStruct); m_pClientDE->SetObjectScale(m_hObject, &m_vScale); // See what it hit DVector vU, vR; pClientDE->GetRotationVectors(&m_Rotation, &vU, &vR, &m_vForward); ClientIntersectQuery iq; ClientIntersectInfo ii; iq.m_Flags = INTERSECT_OBJECTS | INTERSECT_HPOLY; VEC_COPY(iq.m_From, vPos); // Get start point at the last known position. VEC_MULSCALAR(iq.m_To, m_vForward, -1.0f); VEC_ADD(iq.m_To, iq.m_To, iq.m_From); // Get destination point slightly past where we should be // Hit something! try to clip against it. (since this is only being used for bullet marks, if (pClientDE->IntersectSegment(&iq, &ii)) { HPOLY hPoly = ii.m_hPoly; pClientDE->ClipSprite(m_hObject, hPoly); } m_pClientDE->SetObjectColor(m_hObject, 0.1f, 0.1f, 0.1f, 1.0f); return DTRUE; }