void CClientMeleeCollisionController::HandleBlocked(HOBJECT hTarget, const LTVector& vPos, const LTVector& vDir) { // Get the proper weapon record... CClientWeapon* pClientWeapon = g_pClientWeaponMgr->GetCurrentClientWeapon(); HWEAPON hWeapon = pClientWeapon ? pClientWeapon->GetWeaponRecord() : NULL; //!!ARL: Use Attacker's weapon instead? (will need to be sent from server - probably along with block info) HWEAPONDATA hWeaponData = g_pWeaponDB->GetWeaponData(hWeapon, !USE_AI_DATA); // Spawn a block effect for it... const char* pszBlockFX = g_pWeaponDB->GetString(hWeaponData, "BlockFX"); CLIENTFX_CREATESTRUCT fxcs(pszBlockFX, 0, LTRigidTransform(vPos, LTRotation(vDir, LTVector(0,1,0)))); g_pGameClientShell->GetSimulationTimeClientFXMgr().CreateClientFX(NULL, fxcs, true); // Let the server objects know they've blocked / been blocked. CAutoMessage cMsg; cMsg.Writeuint8(MID_OBJECT_MESSAGE); cMsg.WriteObject(m_hObject); cMsg.Writeuint32(MID_MELEEBLOCK); cMsg.WriteObject(hTarget); g_pLTClient->SendToServer(cMsg.Read(), MESSAGE_GUARANTEED); // Disable attacker's collision (i.e. stop attacking). DisableCollisions(); // For local player attackers, send a BlockRecoil stimulus so a proper animation can be played. if (m_hObject == g_pPlayerMgr->GetMoveMgr()->GetObject()) { CPlayerBodyMgr::Instance().HandleAnimationStimulus("CS_RecoilFromBlock"); } }
void CDestructibleModel::DoExplosion(char* pTargetName) { CWeapons weapons; weapons.Init(m_hObject); weapons.ObtainWeapon(m_nExplosionWeaponId); weapons.ChangeWeapon(m_nExplosionWeaponId); CWeapon* pWeapon = weapons.GetCurWeapon(); if (!pWeapon) return; weapons.SetAmmo(pWeapon->GetAmmoId()); pWeapon->SetDamageFactor(m_fDamageFactor); LTRotation rRot; g_pLTServer->GetObjectRotation(m_hObject, &rRot); LTVector vF, vPos; g_pLTServer->GetObjectPos(m_hObject, &vPos); vF = rRot.Forward(); // Just blow up in place if we're not supposed to fire along // forward vector and we don't have a target... if (!m_bFireAlongForward) { pWeapon->SetLifetime(0.0f); VEC_SET(vF, 0.0f, -1.0f, 0.0f); // Fire down } // See if we have a target...If so, point at it. if (pTargetName) { ObjArray <HOBJECT, MAX_OBJECT_ARRAY_SIZE> objArray; g_pLTServer->FindNamedObjects(pTargetName, objArray); if (objArray.NumObjects()) { LTVector vObjPos; g_pLTServer->GetObjectPos(objArray.GetObject(0), &vObjPos); vF = vObjPos - vPos; vF.Normalize(); rRot = LTRotation(vF, LTVector(0.0f, 1.0f, 0.0f)); g_pLTServer->SetObjectRotation(m_hObject, &rRot); } } WeaponFireInfo weaponFireInfo; weaponFireInfo.hFiredFrom = m_hObject; weaponFireInfo.vPath = vF; weaponFireInfo.vFirePos = vPos; weaponFireInfo.vFlashPos = vPos; pWeapon->Fire(weaponFireInfo); }
bool WorldModel::AttachServerMark( CServerMark& mark, CLIENTWEAPONFX & theStruct) { LTransform globalTransform, parentTransform, localTransform; ILTTransform *pTransformLT; LTVector vParentPos, vOffset; LTRotation rParentRot, rRot; LTRotation rOffset; pTransformLT = g_pLTServer->GetTransformLT(); // Attach the mark to the parent object... // Figure out what the rotation we want is. rOffset.Init(); rRot = LTRotation(theStruct.vSurfaceNormal, LTVector(0.0f, 1.0f, 0.0f)); // MD // Ok, now we have the transform in global space but attachments are specified in // local space (so they can move as the object moves and rotates). // Set the global LTransform. pTransformLT->Set(globalTransform, theStruct.vPos, rRot); // Get the object's transform. g_pLTServer->GetObjectPos( m_hObject, &vParentPos); g_pLTServer->GetObjectRotation( m_hObject, &rParentRot); parentTransform.m_Pos = vParentPos; parentTransform.m_Rot = rParentRot; parentTransform.m_Scale.Init(1,1,1); globalTransform.m_Scale.Init(1,1,1); // Get the offset. pTransformLT->Difference(localTransform, globalTransform, parentTransform); vOffset = localTransform.m_Pos; rOffset = localTransform.m_Rot; HATTACHMENT hAttachment = NULL; LTRESULT dRes = g_pLTServer->CreateAttachment( m_hObject, mark.m_hObject, LTNULL, &vOffset, &rOffset, &hAttachment); if (dRes != LT_OK) { return false; } // Add to the attachment list. LTObjRefNotifier ref( *this ); ref = mark.m_hObject; m_AttachmentList.push_back( ref ); return true; }
//this will take a list of properties and convert it to internal values bool CBaseFXProps::LoadProperty(ILTInStream* pStream, const char* pszName, const char* pszStringTable, const uint8* pCurveData) { if( LTStrIEquals( pszName, FXPROP_UPDATEPOS )) { m_eFollowType = (EFXFollowType)CFxProp_Enum::Load(pStream); } else if( LTStrIEquals( pszName, FXPROP_ATTACHNAME )) { m_pszAttach = CFxProp_String::Load(pStream, pszStringTable); } else if( LTStrIEquals( pszName, FXPROP_OFFSET )) { m_vfcOffset.Load(pStream, pCurveData); } else if( LTStrIEquals( pszName, FXPROP_MENULAYER )) { m_nMenuLayer = CFxProp_Int::Load(pStream); } else if( LTStrIEquals( pszName, FXPROP_ROTATION )) { m_vfcRotation.Load(pStream, pCurveData); } else if (LTStrIEquals(pszName, FXPROP_INITIALROTATION)) { LTVector vInitialAngles = CFxProp_Vector::Load(pStream); m_rInitialRotation = LTRotation(VEC_EXPAND(vInitialAngles * MATH_PI / 180.0f)); } else if( LTStrIEquals( pszName, FXPROP_SMOOTHSHUTDOWN )) { m_bSmoothShutdown = CFxProp_EnumBool::Load(pStream); } else if( LTStrIEquals( pszName, FXPROP_DETAILLEVEL )) { m_nDetailLevel = CFxProp_Enum::Load(pStream); LTASSERT((m_nDetailLevel < FX_NUM_DETAIL_SETTINGS), "Found an invalid detail setting"); } else if( LTStrIEquals( pszName, FXPROP_ISGORE )) { m_eGoreSetting = (EFXGoreSetting)CFxProp_Enum::Load(pStream); } else if( LTStrIEquals( pszName, FXPROP_SLOWMOTION )) { m_eSlowMotion = (EFXSlowMotionSetting)CFxProp_Enum::Load(pStream); } else { return false; } return true; }
/* Construct quaternion from Euler angles (in radians). */ LTRotation Eul_ToQuat(EulerAngles ea) { float a[3], ti, tj, th, ci, cj, ch, si, sj, sh, cc, cs, sc, ss; float roll; int i,j,k,h,n,s,f; EulGetOrd((int)ea.w,i,j,k,h,n,s,f); if (f==EulFrmR) { float t = ea.x; ea.x = ea.z; ea.z = t; } if (n==EulParOdd) ea.y = -ea.y; ti = ea.x*0.5f; tj = ea.y*0.5f; th = ea.z*0.5f; ci = (float)cos(ti); cj = (float)cos(tj); ch = (float)cos(th); si = (float)sin(ti); sj = (float)sin(tj); sh = (float)sin(th); cc = ci*ch; cs = ci*sh; sc = si*ch; ss = si*sh; if (s==EulRepYes) { a[i] = cj*(cs + sc); /* Could speed up with */ a[j] = sj*(cc + ss); /* trig identities. */ a[k] = sj*(cs - sc); roll = cj*(cc - ss); } else { a[i] = cj*sc - sj*cs; a[j] = cj*ss + sj*cc; a[k] = cj*cs - sj*sc; roll = cj*cc + sj*ss; } if(n==EulParOdd) a[j] = -a[j]; return LTRotation(a[EulX], a[EulY], a[EulZ], roll); }
void CLeanMgr::CalculateNewPosRot( LTVector &vOutPos, LTRotation &rOutRot, float fAngle ) { float fPitch = g_pPlayerMgr->GetPitch(); float fYaw = g_pPlayerMgr->GetYaw(); float fRoll = g_pPlayerMgr->GetRoll(); // Use the current camera angles and just add the new roll for the camera rotation... rOutRot = LTRotation( fPitch, fYaw, fRoll + fAngle ); // Don't factor in the pitch so the position isn't affected by it... LTMatrix mRotation; LTRotation rRotation( 0.0f, fYaw, fRoll + fAngle ); rRotation.ConvertToMatrix( mRotation ); vOutPos = (mRotation * m_vRotationPtOffset) + m_vRotationPt; // Make sure we are actually in the world before we try to clip... ClientIntersectQuery iQuery; ClientIntersectInfo iInfo; iQuery.m_Flags = INTERSECT_OBJECTS | IGNORE_NONSOLID | INTERSECT_HPOLY; iQuery.m_From = m_vRotationPt + m_vRotationPtOffset; iQuery.m_To = vOutPos; if( g_pLTClient->IntersectSegment( &iQuery, &iInfo )) { vOutPos = iInfo.m_Point + iInfo.m_Plane.m_Normal; } // Keep us far away from walls to avoid clipping... float fCamClipDist = g_vtCameraClipDistance.GetFloat(); g_vtCameraClipDistance.SetFloat( g_vtLeanCamClipDist.GetFloat() ); g_pPlayerMgr->GetPlayerCamera()->CalcNonClipPos( vOutPos, rOutRot ); g_vtCameraClipDistance.SetFloat( fCamClipDist ); }
LTRotation CLTMessage_Read::PeekYRotation(const CPacket_Read &cPacket) { int8 nAngle = cPacket.Peekint8(); return LTRotation(0.0f, (float)(nAngle) * (MATH_PI / 127.0f), 0.0f); }
LTRotation CLTMessage_Read::ReadYRotation(CPacket_Read &cPacket) { int8 nAngle = cPacket.Readint8(); return LTRotation(0.0f, (float)(nAngle) * (MATH_PI / 127.0f), 0.0f); }
void CLightningFX::EmitBolts( float tmFrameTime ) { // Make sure enough time between emissions has passed... m_tmElapsedEmission += tmFrameTime; if( m_fDelay < m_tmElapsedEmission ) { LTransform lTrans; LTVector vAttractorPos; ILTModel *pModelLT = m_pLTClient->GetModelLT(); uint32 nActiveBolts = GetRandom( (int)GetProps()->m_nMinNumBolts, (int)GetProps()->m_nMaxNumBolts ); uint32 nBolt; bool bCanUseAttractors = (m_lstAttractors.size() > 0); bool bCanUseRadius = (GetProps()->m_fOmniDirectionalRadius >= 1.0f); CLightningBolt *pBolt = LTNULL; LightningBolts::iterator iter; for( nBolt = 0, iter = m_lstBolts.begin(); iter != m_lstBolts.end(), nBolt < nActiveBolts; ++iter, ++nBolt ) { pBolt = *iter; pBolt->m_fWidth = GetRandom( GetProps()->m_fMinBoltWidth, GetProps()->m_fMaxBoltWidth ); pBolt->m_fLifetime = GetRandom( GetProps()->m_fMinLifetime, GetProps()->m_fMaxLifetime ); pBolt->m_tmElapsed = 0.0f; pBolt->m_bActive = true; // Grab the position of the object to compensate for offset if( m_hTarget ) { m_pLTClient->GetObjectPos( m_hTarget, &vAttractorPos ); } else { vAttractorPos = m_vTargetPos; } // Decide if we should use an attractor or radius for the end pos... if( bCanUseAttractors && (!bCanUseRadius || GetRandom(0,1)) ) { uint8 nIndex = GetRandom( 0, (int)(m_lstAttractors.size()) - 1 ); CAttractor cAttractor = m_lstAttractors[nIndex]; if( cAttractor.GetTransform( lTrans, true ) == LT_OK ) { vAttractorPos = lTrans.m_Pos; } } else if( bCanUseRadius ) { LTVector vRandomPos; vRandomPos.x = GetRandom( -1.0f, 1.0f ); vRandomPos.y = GetRandom( -1.0f, 1.0f ); vRandomPos.z = GetRandom( -1.0f, 1.0f ); vRandomPos.Normalize(); vRandomPos *= GetRandom( -GetProps()->m_fOmniDirectionalRadius, GetProps()->m_fOmniDirectionalRadius ); vAttractorPos = m_vPos + vRandomPos; IntersectQuery iQuery; IntersectInfo iInfo; iQuery.m_From = m_vPos; iQuery.m_To = vAttractorPos; if( m_pLTClient->IntersectSegment( &iQuery, &iInfo )) { vAttractorPos = iInfo.m_Point; } } LTVector vNew = m_vPos; LTVector vDir = vAttractorPos - vNew; float fStep = vDir.Length() / (float)pBolt->m_nNumSegments; float fPerturb = GetRandom( GetProps()->m_fMinPerturb, GetProps()->m_fMaxPerturb ); vDir.Normalize(); LTRotation rRot = LTRotation( vDir, LTVector( 0.0f, 1.0f, 0.0f )); CLinkListNode<PT_TRAIL_SECTION> *pNode = pBolt->m_collPathPts.GetHead(); while( pNode ) { pNode->m_Data.m_vPos = vNew; pNode->m_Data.m_tmElapsed = 0.0f; pNode->m_Data.m_vBisector.Init(); // Add in some perturb going in the direction of the attractor pos for the next section... vNew += (rRot.Forward() * fStep ); vNew += (rRot.Up() * GetRandom( -fPerturb, fPerturb )); vNew += (rRot.Right() * GetRandom( -fPerturb, fPerturb )); // Make sure the last section goes to the end pos... if( !pNode->m_pNext ) pNode->m_Data.m_vPos = vAttractorPos; pNode = pNode->m_pNext; } } // Decide when the next emission will be... m_tmElapsedEmission = 0.0f; m_fDelay = GetRandom( GetProps()->m_fMinDelay, GetProps()->m_fMaxDelay ); } }
bool CLTBModelFX::Init(ILTClient *pClientDE, FX_BASEDATA *pBaseData, const CBaseFXProps *pProps) { // Perform base class initialisation if (!CBaseFX::Init(pClientDE, pBaseData, pProps)) return false; // Use the "target" Normal instead, if one was specified... LTVector vNorm = GetProps()->m_vNorm; if( pBaseData->m_vTargetNorm.LengthSquared() > MATH_EPSILON ) { vNorm = pBaseData->m_vTargetNorm; vNorm.Normalize(); } // Develop the Right and Up vectors based off the Forward... LTVector vR, vU; if( (1.0f == vNorm.y) || (-1.0f == vNorm.y) ) { vR = LTVector( 1.0f, 0.0f, 0.0f ).Cross( vNorm ); } else { vR = LTVector( 0.0f, 1.0f, 0.0f ).Cross( vNorm ); } vU = vNorm.Cross( vR ); m_rNormalRot = LTRotation( vNorm, vU ); ObjectCreateStruct ocs; // Combine the direction we would like to face with our parents rotation... if( m_hParent ) { m_pLTClient->GetObjectRotation( m_hParent, &ocs.m_Rotation ); } else { ocs.m_Rotation = m_rCreateRot; } ocs.m_Rotation = ocs.m_Rotation * m_rNormalRot; ocs.m_ObjectType = OT_MODEL; ocs.m_Flags |= pBaseData->m_dwObjectFlags | (GetProps()->m_bShadow ? FLAG_SHADOW : 0 ); ocs.m_Flags2 |= pBaseData->m_dwObjectFlags2; // Calculate the position with the offset in 'local' coordinate space... LTMatrix mMat; ocs.m_Rotation.ConvertToMatrix( mMat ); m_vPos = ocs.m_Pos = m_vCreatePos + (mMat * GetProps()->m_vOffset); SAFE_STRCPY( ocs.m_Filename, GetProps()->m_szModelName ); SAFE_STRCPY( ocs.m_SkinNames[0], GetProps()->m_szSkinName[0] ); SAFE_STRCPY( ocs.m_SkinNames[1], GetProps()->m_szSkinName[1] ); SAFE_STRCPY( ocs.m_SkinNames[2], GetProps()->m_szSkinName[2] ); SAFE_STRCPY( ocs.m_SkinNames[3], GetProps()->m_szSkinName[3] ); SAFE_STRCPY( ocs.m_SkinNames[4], GetProps()->m_szSkinName[4] ); SAFE_STRCPY( ocs.m_RenderStyleNames[0], GetProps()->m_szRenderStyle[0] ); SAFE_STRCPY( ocs.m_RenderStyleNames[1], GetProps()->m_szRenderStyle[1] ); SAFE_STRCPY( ocs.m_RenderStyleNames[2], GetProps()->m_szRenderStyle[2] ); SAFE_STRCPY( ocs.m_RenderStyleNames[3], GetProps()->m_szRenderStyle[3] ); m_hObject = m_pLTClient->CreateObject(&ocs); if( !m_hObject ) return LTFALSE; ILTModel *pLTModel = m_pLTClient->GetModelLT(); ANIMTRACKERID nTracker; pLTModel->GetMainTracker( m_hObject, nTracker ); //setup the animation if the user specified one if( strlen(GetProps()->m_szAnimName) > 0) { //ok, we need to set this HMODELANIM hAnim = m_pLTClient->GetAnimIndex(m_hObject, GetProps()->m_szAnimName); if(hAnim != INVALID_MODEL_ANIM) { //ok, lets set this animation pLTModel->SetCurAnim(m_hObject, nTracker, hAnim); pLTModel->ResetAnim(m_hObject, nTracker); } } //disable looping on this animation (so we can actually stop!) pLTModel->SetLooping(m_hObject, nTracker, false); // Setup the initial data needed to override the models animation length... if( GetProps()->m_bOverrideAniLength ) { uint32 nAnimLength; pLTModel->GetCurAnimLength( m_hObject, nTracker, nAnimLength ); pLTModel->SetCurAnimTime( m_hObject, nTracker, 0 ); float fAniLength = (GetProps()->m_fAniLength < MATH_EPSILON) ? GetProps()->m_tmLifespan : GetProps()->m_fAniLength; if( fAniLength >= MATH_EPSILON || fAniLength <= -MATH_EPSILON ) m_fAniRate = (nAnimLength * 0.001f) / fAniLength; pLTModel->SetAnimRate( m_hObject, nTracker, m_fAniRate ); } // Success !! return LTTRUE; }
void CWeatherFX::CreateSplashSprites() { if (m_eSurfaceType == ST_UNKNOWN) return; // Setup the splash sprite... BSCREATESTRUCT sc; CString str; LTFLOAT fLifetime = 0.0; uint32 dwFlags = FLAG_NOLIGHT; char szFilename[128] = ""; if (m_eSurfaceType == ST_LIQUID) { sc.rRot = LTRotation(LTVector(0.0f, 1.0f, 0.0f), LTVector(1.0f, 0.0f, 0.0f)); fLifetime = 1.0f; dwFlags |= FLAG_ROTATEABLESPRITE; g_pClientButeMgr->GetWeatherAttributeString(WEATHER_BUTE_RAINRING,szFilename,sizeof(szFilename)); if (!szFilename[0]) return; } else // Not a liquid { fLifetime = 0.05f; dwFlags |= FLAG_SPRITEBIAS; g_pClientButeMgr->GetWeatherAttributeString(WEATHER_BUTE_RAINSPLASH,szFilename,sizeof(szFilename)); if (!szFilename[0]) return; } sc.vPos = m_vPos; sc.dwFlags = dwFlags; sc.fLifeTime = fLifetime; sc.fInitialAlpha = 1.0f; sc.fFinalAlpha = 0.0f; sc.pFilename = szFilename; sc.nType = OT_SPRITE; LTFLOAT fStartScale, fEndScale; for (int i=0; i < NUM_SPLASH_SPRITES; i++) { if (m_eSurfaceType == ST_LIQUID) { fStartScale = GetRandom(0.05f, 0.1f); fEndScale = GetRandom(0.2f, 0.3f); } else { fStartScale = GetRandom(0.1f, 0.30f); fEndScale = GetRandom(0.2f, 0.35f); } sc.vInitialScale.Init(fStartScale, fStartScale, 1.0f); sc.vFinalScale.Init(fEndScale, fEndScale, 1.0f); if (!m_Splash[i].Init(&sc) || !m_Splash[i].CreateObject(m_pClientDE)) { break; } } }
//performs a ray intersection. This will return false if nothing is hit, or true if something //is. If something is hit, it will fill out the intersection property and the alignment //vector according to the properties that the user has setup. If an object is hit, it will //fill out the hit object, and specify the output transform relative to the hit object's space bool CCreateRayFX::DetermineIntersection( const LTVector& vObjPos, const LTVector& vObjForward, HOBJECT& hOutObj, LTRigidTransform& tOutTrans) { //default our output parameters to reasonable values hOutObj = NULL; tOutTrans.Init(); //perform a ray intersection from our position along our Y axis and see if we hit anything. //If we do, create the effect there facing along the specified vector, randomly twisted //find the starting and ending points LTVector vStart = vObjPos + vObjForward * GetProps()->m_fMinDist; LTVector vEnd = vObjPos + vObjForward * GetProps()->m_fMaxDist; //we now need to perform an intersection using these endpoints and see if we hit anything IntersectQuery iQuery; IntersectInfo iInfo; iQuery.m_Flags = INTERSECT_HPOLY | IGNORE_NONSOLID; iQuery.m_FilterFn = NULL; iQuery.m_pUserData = NULL; iQuery.m_From = vStart; iQuery.m_To = vEnd; if( !g_pLTClient->IntersectSegment( iQuery, &iInfo ) ) { //we didn't intersect anything, don't create an effect return false; } //determine if we hit the sky if(IsSkyPoly(iInfo.m_hPoly)) { //never create an effect on the sky return false; } //we now need to determine the normal of intersection LTVector vHitNormal = iInfo.m_Plane.Normal(); //we hit something, so we can now at least determine the point of intersection tOutTrans.m_vPos = iInfo.m_Point + vHitNormal * GetProps()->m_fOffset; //the primary vector we wish to align to LTVector vAlignment; //determine what our dominant axis should be switch (GetProps()->m_eAlignment) { default: case CCreateRayProps::eAlign_ToSource: vAlignment = -vObjForward; break; case CCreateRayProps::eAlign_Normal: vAlignment = vHitNormal; break; case CCreateRayProps::eAlign_Outgoing: vAlignment = vObjForward - (2.0f * vObjForward.Dot(vHitNormal)) * vHitNormal; vAlignment.Normalize(); break; case CCreateRayProps::eAlign_ToViewer: { LTVector vCameraPos; g_pLTClient->GetObjectPos(m_pFxMgr->GetCamera(), &vCameraPos); vAlignment = vCameraPos - tOutTrans.m_vPos; vAlignment.Normalize(); } break; } //and generate a randomly twisted orientation around our dominant axis tOutTrans.m_rRot = LTRotation(vAlignment, LTVector(0.0f, 1.0f, 0.0f)); tOutTrans.m_rRot.Rotate(vAlignment, GetRandom(0.0f, MATH_CIRCLE)); //now if we hit an object, make sure to store that object, and convert the transform into //the object's space if(iInfo.m_hObject && (g_pLTClient->Physics()->IsWorldObject(iInfo.m_hObject) == LT_NO)) { //store this as our hit object hOutObj = iInfo.m_hObject; //and convert the transform into that object's space LTRigidTransform tObjTrans; g_pLTClient->GetObjectTransform(hOutObj, &tObjTrans); tOutTrans = tOutTrans.GetInverse() * tOutTrans; } //success return true; }
bool DoomsDayDevice::AddDoomsDayPiece( DoomsDayPiece *pDDPiece, CPlayerObj *pPlayer ) { if( !pDDPiece || !pPlayer ) return false; // Don't allow dead players to add pieces to a device... if( pPlayer->IsDead() ) return false; // Check the list of pieces to see if this one has already been added... DoomsDayPieceList::iterator iter = m_lstPiecesOnDevice.begin(); while( iter != m_lstPiecesOnDevice.end() ) { if( (*iter)->GetDoomsDayPieceType() == pDDPiece->GetDoomsDayPieceType() ) return false; ++iter; } // Reset the filenames to the 'replaced' PropType... char szPropType[256] = {0}; sprintf( szPropType, "%s_replace", pDDPiece->GetPropTypeName() ); PROPTYPE *pPropType = g_pPropTypeMgr->GetPropType( szPropType ); if( !pPropType ) return false; ObjectCreateStruct ocs; LTStrCpy( ocs.m_Filename, pPropType->sFilename.c_str(), ARRAY_LEN( ocs.m_Filename )); pPropType->blrPropRenderStyleReader.CopyList( 0, ocs.m_RenderStyleNames[0], MAX_CS_FILENAME_LEN + 1 ); pPropType->blrPropSkinReader.CopyList( 0, ocs.m_SkinNames[0], MAX_CS_FILENAME_LEN + 1 ); if( g_pCommonLT->SetObjectFilenames( pDDPiece->m_hObject, &ocs ) != LT_OK ) return false; // Attach the piece to the base... LTVector vPos; g_pLTServer->GetObjectPos( m_hObject, &vPos ); g_pLTServer->SetObjectPos( pDDPiece->m_hObject, &vPos ); LTRotation rRot; g_pLTServer->GetObjectRotation( m_hObject, &rRot ); g_pLTServer->SetObjectRotation( pDDPiece->m_hObject, &rRot ); LTStrCpy( szPropType, pDDPiece->GetPropTypeName(), ARRAY_LEN( szPropType )); char *pszDoomsday = strtok( szPropType, "_" ); char *pszSocket = strtok( NULL, "\0" ); HATTACHMENT hAttachment; g_pLTServer->CreateAttachment( m_hObject, pDDPiece->m_hObject, pszSocket, <Vector(0,0,0), <Rotation(), &hAttachment ); // Hide the target object... g_pCommonLT->SetObjectFlags( m_lsthTargets[pDDPiece->GetDoomsDayPieceType()], OFT_Flags, 0, FLAG_VISIBLE ); // Add it to the list of pieces... m_lstPiecesOnDevice.push_back( pDDPiece ); // Give the player points for adding the piece. ServerGameOptions& sgo = g_pGameServerShell->GetServerGameOptions( ); uint32 nBonus = pDDPiece->IsHeavy( ) ? sgo.GetDoomsday( ).m_nHeavyPiecePlacedScore : sgo.GetDoomsday( ).m_nLightPiecePlacedScore; pPlayer->GetPlayerScore()->AddBonus( nBonus ); if( m_lstPiecesOnDevice.size() == kDoomsDay_MAXTYPES ) { // All the pieces are now on the base... Fire( *pPlayer ); } return true; }
void DoomsDayDevice::InitialUpdate( ) { // Create the "target" objects... char szSpawn[256]; LTVector vPos; g_pLTServer->GetObjectPos( m_hObject, &vPos ); LTRotation rRot; g_pLTServer->GetObjectRotation( m_hObject, &rRot ); // The PropTypes to use as targets are the normal PropTypes with _target appended... char szType[64] = {0}; for( uint32 i = 0; i < kDoomsDay_MAXTYPES; ++i ) { sprintf( szType, c_aDDPieceTypes[i].m_pszPropType ); sprintf( szSpawn, "PropType Type %s_target", szType ); BaseClass* pObj = SpawnObject( szSpawn, vPos, rRot ); if( pObj && pObj->m_hObject ) { m_lsthTargets.push_back( pObj->m_hObject ); g_pCommonLT->SetObjectFlags( m_lsthTargets[i], OFT_Flags2, FLAG2_FORCETRANSLUCENT, FLAG2_FORCETRANSLUCENT ); // Attach the target to the base... char *pszDoomsday = strtok( szType, "_" ); char *pszSocket = strtok( NULL, "\0" ); HATTACHMENT hAttachment; g_pLTServer->CreateAttachment( m_hObject, pObj->m_hObject, pszSocket, <Vector(0,0,0), <Rotation(), &hAttachment ); } } BeginIdle( ); }
bool WorldModel::CreateServerMark(CLIENTWEAPONFX & theStruct) { // See if we should create a mark, or simply move one of the GameBase's // marks. // If the GameBase has the max number of marks or this mark is very close // to a pre-existing mark, just move that mark to the new position. HOBJECT hMoveObj = LTNULL; HOBJECT hFarObj = LTNULL; uint32 nNumMarks = m_MarkList.size( ); LTFLOAT fClosestMarkDist = REGION_DIAMETER; LTFLOAT fFarthestMarkDist = 0.0f; uint8 nNumInRegion = 0; LTVector vPos; for( ObjRefNotifierList::iterator iter = m_MarkList.begin( ); iter != m_MarkList.end( ); iter++ ) { HOBJECT hObj = *iter; if( !hObj ) continue; HATTACHMENT hAttachment = NULL; if (LT_OK == g_pLTServer->FindAttachment( m_hObject, hObj, &hAttachment)) { LTransform transform; g_pCommonLT->GetAttachmentTransform(hAttachment, transform, LTTRUE); vPos = transform.m_Pos; } LTFLOAT fDist = VEC_DISTSQR(vPos, theStruct.vPos); if (fDist < REGION_DIAMETER) { if (fDist < fClosestMarkDist) { fClosestMarkDist = fDist; hMoveObj = hObj; } if (++nNumInRegion > MAX_MARKS_IN_REGION) { // Just move this mark to the correct pos... hMoveObj = hMoveObj ? hMoveObj : hObj; break; } } if (fDist > fFarthestMarkDist) { fFarthestMarkDist = fDist; hFarObj = hObj; } } // If we've got the max number of marks on this object, just move // the closest one to the new position... if (nNumMarks >= MAX_MARKS_PER_OBJECT) { if( !hMoveObj ) { if( hFarObj ) { hMoveObj = hFarObj; } else { HOBJECT hFirstMark = *m_MarkList.begin( ); hMoveObj = hFirstMark; } } } else { hMoveObj = LTNULL; // Need to create one... } // Re-setup the object to move it... if (hMoveObj && IsKindOf(hMoveObj, "CServerMark")) { CServerMark* pMoveMark = (CServerMark*) g_pLTServer->HandleToObject(hMoveObj); if (!pMoveMark) return false; // Since this mark is already attached to us, remove the attachment DetachObject( pMoveMark->m_hObject ); if( !AttachServerMark( *pMoveMark, (CLIENTWEAPONFX)theStruct)) { g_pLTServer->RemoveObject( pMoveMark->m_hObject ); RemoveMarkFromList( pMoveMark->m_hObject ); pMoveMark = NULL; return false; } return true; } // Okay, no luck, need to create a new mark... ObjectCreateStruct createStruct; INIT_OBJECTCREATESTRUCT(createStruct); LTFLOAT fScaleAdjust = 1.0f; if (!GetImpactSprite((SurfaceType)theStruct.nSurfaceType, fScaleAdjust, theStruct.nAmmoId, createStruct.m_Filename, ARRAY_LEN(createStruct.m_Filename))) { return false; } createStruct.m_ObjectType = OT_SPRITE; createStruct.m_Flags = FLAG_VISIBLE | FLAG_NOLIGHT | FLAG_ROTATEABLESPRITE; createStruct.m_Pos = theStruct.vPos; createStruct.m_Rotation = LTRotation(theStruct.vSurfaceNormal, LTVector(0.0f, 1.0f, 0.0f)); AMMO const *pAmmo = g_pWeaponMgr->GetAmmo(theStruct.nAmmoId); if( !pAmmo ) return false; static HCLASS hClass = g_pLTServer->GetClass("CServerMark"); CServerMark* pMark = (CServerMark*) g_pLTServer->CreateObject(hClass, &createStruct); if (!pMark) return false; // Randomly adjust the mark's scale to add a bit o spice... if (pAmmo->pImpactFX) { LTFLOAT fScale = fScaleAdjust * pAmmo->pImpactFX->fMarkScale; LTVector vScale(fScale, fScale, fScale); g_pLTServer->ScaleObject(pMark->m_hObject, &vScale); } if( !AttachServerMark( *pMark, (CLIENTWEAPONFX)theStruct)) { g_pLTServer->RemoveObject( pMark->m_hObject ); pMark = NULL; return false; } AddMarkToList( pMark->m_hObject ); return true; }
bool CFallingStuffFX::Update(float tmFrameTime) { // Base class update first m_vLastPos = m_vPos; if (!CBaseFX::Update(tmFrameTime)) return false; //increment our emission time by the elapsed frame time m_tmElapsedEmission += tmFrameTime; if (!IsShuttingDown() && !IsSuspended() && (m_tmElapsedEmission > GetProps()->m_tmFallingStuffFXEmission)) { ObjectCreateStruct ocs; INIT_OBJECTCREATESTRUCT(ocs); LTVector vScale; vScale.Init(m_scale, m_scale, m_scale); LTVector vInterp; LTVector vInterpCur = m_vPos; // Calculate interpolant for particle system if (GetProps()->m_nFallingStuffFXEmission) { vInterp = m_vPos - m_vLastPos; vInterp /= (float)GetProps()->m_nFallingStuffFXEmission; } for (uint32 i = 0; i < GetProps()->m_nFallingStuffFXEmission; i ++) { ocs.m_ObjectType = OT_SPRITE; ocs.m_Flags = FLAG_VISIBLE | FLAG_NOLIGHT | FLAG_ROTATABLESPRITE; // Compute the initial position float xRand = GetProps()->m_fRadius * ((-10000.0f + (rand() % 20000)) / 10000.0f); float zRand = GetProps()->m_fRadius * ((-10000.0f + (rand() % 20000)) / 10000.0f); ocs.m_Pos = m_vPos + (m_vRight * xRand) + (m_vUp * zRand); ocs.m_Scale = vScale; strcpy(ocs.m_Filename, GetProps()->m_sSpriteName); // Move the start point vInterpCur += vInterp; HLOCALOBJ hNewSprite = m_pLTClient->CreateObject(&ocs); if (hNewSprite) { // Create a new sprite FALLING_THING *pNewSprite = debug_new( FALLING_THING ); if (GetProps()->m_nImpactCreate) { if (g_dwSplash > (uint32)GetProps()->m_nImpactCreate) { pNewSprite->m_bSplash = true; g_dwSplash = 0; } else { pNewSprite->m_bSplash = false; } } else { pNewSprite->m_bSplash = false; } g_dwSplash ++; if (pNewSprite) { LTVector v; // Compute the initial velocity v = m_vPlaneDir * GetProps()->m_fVel; pNewSprite->m_hObject = hNewSprite; pNewSprite->m_vVel = v; pNewSprite->m_tmElapsed = 0.0f; pNewSprite->m_vPos = ocs.m_Pos; pNewSprite->m_vLastPos = ocs.m_Pos; m_collSprites.AddTail(pNewSprite); } } } m_tmElapsedEmission = 0.0f; // And store the last position m_vLastPos = m_vPos; } LTMatrix mSpin; if (GetProps()->m_bUseSpin) { // Setup rotation LTMatrix vRight; LTMatrix vUp; LTMatrix vForward; LTMatrix vTmp; Mat_SetupRot(&vRight, &m_vRight, m_xRot); Mat_SetupRot(&vUp, &m_vUp, m_yRot); Mat_SetupRot(&vForward, &m_vPlaneDir, m_zRot); MatMul(&vTmp, &vRight, &vUp); MatMul(&mSpin, &vTmp, &vForward); m_xRot += GetProps()->m_vRotAdd.x * tmFrameTime; m_yRot += GetProps()->m_vRotAdd.y * tmFrameTime; m_zRot += GetProps()->m_vRotAdd.z * tmFrameTime; } // Get the camera rotation LTRotation orient; m_pLTClient->GetObjectRotation(m_hCamera, &orient); LTRotation dRot(orient); LTVector vF = orient.Forward(); float rot = (float)atan2(vF.x, vF.z); // Update the sprites.... CLinkListNode<FALLING_THING *> *pNode = m_collSprites.GetHead(); CLinkListNode<FALLING_THING *> *pDelNode; while (pNode) { pDelNode = NULL; FALLING_THING *pSprite = pNode->m_Data; //adjust our elapsed time pSprite->m_tmElapsed += tmFrameTime; // Check for expiration if (pSprite->m_tmElapsed > GetProps()->m_tmSpriteLifespan) { // Destroy this object m_pLTClient->RemoveObject(pSprite->m_hObject); pDelNode = pNode; } else { // Update !! pSprite->m_vLastPos = pSprite->m_vPos; pSprite->m_vPos += (pSprite->m_vVel * tmFrameTime); // Rotate if neccessary TVector3<float> vPos = pSprite->m_vPos; if (GetProps()->m_bUseSpin) { MatVMul_InPlace(&mSpin, &vPos); } // Add in wind vPos += (GetProps()->m_vWind * GetProps()->m_fWindAmount) * tmFrameTime; // Setup the new sprite position LTVector vPos2 = vPos; m_pLTClient->SetObjectPos(pSprite->m_hObject, &vPos2); // Setup the colour float r, g, b, a; m_pLTClient->GetObjectColor(pSprite->m_hObject, &r, &g, &b, &a); CalcColour(pSprite->m_tmElapsed, GetProps()->m_tmSpriteLifespan, &r, &g, &b, &a); m_pLTClient->SetObjectColor(pSprite->m_hObject, r, g, b, a); // Setup the scale float scale = 0.1f; CalcScale(pSprite->m_tmElapsed, GetProps()->m_tmSpriteLifespan, &scale); LTVector vScale; vScale.Init(scale, scale * GetProps()->m_fStretchMul, scale); m_pLTClient->SetObjectScale(pSprite->m_hObject, &vScale); // Setup the rotation dRot = LTRotation(0, 0, 0, 1); LTRotation orient(dRot); orient.Rotate( orient.Up(), rot ); m_pLTClient->SetObjectRotation(pSprite->m_hObject, &orient); // Check to see if we need to start a splash sprite if (pSprite->m_bSplash) { ClientIntersectQuery ciq; ClientIntersectInfo cii; ciq.m_From = pSprite->m_vLastPos; ciq.m_To = pSprite->m_vPos; if ((GetProps()->m_sImpactSpriteName[0]) && (m_pLTClient->IntersectSegment(&ciq, &cii))) { // Create a splash sprite SPLASH *pSplash = debug_new( SPLASH ); ObjectCreateStruct ocs; INIT_OBJECTCREATESTRUCT(ocs); LTVector vScale; vScale.Init(0.0f, 0.0f, 0.0f); ocs.m_ObjectType = OT_SPRITE; ocs.m_Flags = FLAG_VISIBLE | FLAG_ROTATABLESPRITE | FLAG_NOLIGHT; ocs.m_Pos = cii.m_Point + (cii.m_Plane.m_Normal * 2.0f); ocs.m_Scale = vScale; LTRotation dOrient( cii.m_Plane.m_Normal, LTVector(0.0f, 1.0f, 0.0f) ); strcpy(ocs.m_Filename, GetProps()->m_sImpactSpriteName); pSplash->m_hObject = m_pLTClient->CreateObject(&ocs); pSplash->m_scale = 0.0f; LTRotation orient(dRot); m_pLTClient->SetObjectRotation(pSplash->m_hObject, &orient); pSplash->m_tmElapsed = 0.0f; m_collSplashes.AddTail(pSplash); // Destroy this object m_pLTClient->RemoveObject(pSprite->m_hObject); // Delete the sprite pDelNode = pNode; } } } pNode = pNode->m_pNext; if (pDelNode) m_collSprites.Remove(pDelNode); } // Update our splashes CLinkListNode<SPLASH *> *pSplashNode = m_collSplashes.GetHead(); while (pSplashNode) { CLinkListNode<SPLASH *> *pDelNode = NULL; SPLASH *pSplash = pSplashNode->m_Data; //update the elapsed time on the splash pSplash->m_tmElapsed += tmFrameTime; // Calculate the new scale float scale = GetProps()->m_fImpactScale1 + ((GetProps()->m_fImpactScale2 - GetProps()->m_fImpactScale1) * (pSplash->m_tmElapsed / GetProps()->m_tmImpactLifespan)); LTVector vScale(scale, scale, scale); m_pLTClient->SetObjectScale(pSplash->m_hObject, &vScale); float r, g, b, a; m_pLTClient->GetObjectColor(pSplash->m_hObject, &r, &g, &b, &a); a = (float)(int)(pSplash->m_tmElapsed / GetProps()->m_tmImpactLifespan); if (a < 0.0f) a = 0.0f; if (a > 1.0f) a = 1.0f; m_pLTClient->SetObjectColor(pSplash->m_hObject, r, g, b, a); if (pSplash->m_tmElapsed > GetProps()->m_tmImpactLifespan) { m_pLTClient->RemoveObject(pSplash->m_hObject); pDelNode = pSplashNode; } pSplashNode = pSplashNode->m_pNext; if (pDelNode) m_collSplashes.Remove(pDelNode); } // Success !! return true; }