void Body::CreateHitBox(const BODYINITSTRUCT& bi)
{
	if (m_hHitBox) return;

	LTVector vPos;
    g_pLTServer->GetObjectPos(m_hObject, &vPos);

    HCLASS hClass = g_pLTServer->GetClass("CCharacterHitBox");
	if (!hClass) return;

	ObjectCreateStruct theStruct;
	INIT_OBJECTCREATESTRUCT(theStruct);

	theStruct.m_Pos = vPos;
    g_pLTServer->GetObjectRotation(m_hObject, &theStruct.m_Rotation);

	// Allocate an object...

    CCharacterHitBox* pHitBox = (CCharacterHitBox *)g_pLTServer->CreateObject(hClass, &theStruct);
	if (!pHitBox) return;

	m_hHitBox = pHitBox->m_hObject;

	pHitBox->Init(m_hObject);
	pHitBox->SetCanActivate(LTFALSE);

	if (m_hHitBox)
	{
		LTVector vDims;
		g_pLTServer->GetObjectDims(m_hObject, &vDims);
		g_pLTServer->SetObjectDims(m_hHitBox, &vDims);
	}
}
LTBOOL CProjectile::HandlePotentialHitBoxImpact(IntersectInfo & iInfo,
                                               LTVector & vFrom)
{
    CCharacterHitBox *pCharHitBox = (CCharacterHitBox*) g_pLTServer->HandleToObject(iInfo.m_hObject);
    if (!pCharHitBox) return LTFALSE;

	return pCharHitBox->HandleImpact(this, iInfo, m_vDir, vFrom);
}
void Body::UpdateHitBox()
{
	if ( !m_hHitBox ) return;

    CCharacterHitBox* pHitBox = (CCharacterHitBox*) g_pLTServer->HandleToObject(m_hHitBox);
	if ( pHitBox )
	{
		pHitBox->Update();
	}
}
LTBOOL DoVectorFilterFn(HOBJECT hObj, void *pUserData)
{
	// We're not attacking our self...

	if (SpecificObjectFilterFn(hObj, pUserData))
	{
		// CharacterHitBox objects are used for vector impacts, don't
		// impact on the character/body prop object itself....

		if (IsCharacter(hObj) || IsBody(hObj) || IsKindOf(hObj, "Intelligence"))
		{
            return LTFALSE;
		}

		// Check special character hit box cases...

		if (IsCharacterHitBox(hObj))
		{
            CCharacterHitBox *pCharHitBox = (CCharacterHitBox*) g_pLTServer->HandleToObject(hObj);
			if (pCharHitBox)
			{
				// Make sure we don't hit ourself...

				HOBJECT hUs = (HOBJECT)pUserData;

				HOBJECT hTestObj = pCharHitBox->GetModelObject();
                if (!hTestObj) return LTFALSE;

				if (hTestObj == hUs)
				{
                    return LTFALSE;
				}


				// Do special AI hitting AI case...
				if (IsAI(hUs) && IsAI(hTestObj))
				{
                    CAI *pAI = (CAI*) g_pLTServer->HandleToObject(hUs);
                    if (!pAI) return LTFALSE;

					// We can't hit guys we like, unless they're NEUTRAL

                    CCharacter* pB = (CCharacter*)g_pLTServer->HandleToObject(hTestObj);
                    if (!pB) return LTFALSE;

					CharacterClass cc = pB->GetCharacterClass();
					if (cc != NEUTRAL)
					{
						return LIKE != GetAlignement(pAI->GetCharacterClass(), cc);
					}
				}

				// Check for friendly fire
				if (g_pGameServerShell->GetGameType() == COOPERATIVE_ASSAULT && g_vtNetFriendlyFire.GetFloat() < 1.0f)
				{
					// We can't hit guys on our team unless friendly fire is turned on
					if (IsPlayer(hUs) && IsPlayer(hTestObj))
					{
                        CPlayerObj* pUs = (CPlayerObj*) g_pLTServer->HandleToObject(hUs);
                        if (!pUs) return LTFALSE;


                        CPlayerObj* pThem = (CPlayerObj*) g_pLTServer->HandleToObject(hTestObj);
                        if (!pThem) return LTFALSE;

						if (pUs->GetTeamID() == pThem->GetTeamID())
                            return LTFALSE;
					}

				}
			}
		}

        return LTTRUE;
	}

    return LTFALSE;
}
void CProjectile::HandleTouch(HOBJECT hObj)
{
	if (m_bObjectRemoved) return;

	// Don't process any touches until this has been cleared...

	if (m_bProcessInvImpact) return;

	 // Let it get out of our bounding box...

	if (hObj == m_hFiredFrom) return;

	CCharacterHitBox* pHitBox = LTNULL;

	// If we've hit a character (or body), let its hit box take control...

	if (IsCharacter(hObj))
	{
       CCharacter* pChar = (CCharacter*)g_pLTServer->HandleToObject(hObj);
		if (pChar)
		{
			hObj = pChar->GetHitBox();
		}
	}
	else if (IsBody(hObj))
	{
	    Body* pBody = (Body*)g_pLTServer->HandleToObject(hObj);
		if (pBody)
		{
			hObj = pBody->GetHitBox();
		}
	}


	if (IsCharacterHitBox(hObj))
	{
        pHitBox = (CCharacterHitBox*)g_pLTServer->HandleToObject(hObj);
		if (!pHitBox) return;

		if (pHitBox->GetModelObject() == m_hFiredFrom) return;
	}


	// Don't hit our own type of projectiles (for multi-projectile weapons
	// and projectiles that stick to objects)...

	if (IsKindOf(hObj, m_hObject))
	{
        CProjectile* pObj = (CProjectile*)g_pLTServer->HandleToObject(hObj);
		if (pObj)
		{
			if (pObj->GetFiredFrom() == m_hFiredFrom)
			{
				return;
			}
		}
	}



	// See if we want to impact on this object...

    uint32 dwUsrFlags = g_pLTServer->GetObjectUserFlags(hObj);
	if (dwUsrFlags & USRFLG_IGNORE_PROJECTILES) return;

    LTBOOL bIsWorld = IsMainWorld(hObj);


	// Don't impact on non-solid objects...unless it is a CharacterHitBox
	// object...

    uint32 dwFlags = g_pLTServer->GetObjectFlags(hObj);
	if (!bIsWorld && !(dwFlags & FLAG_SOLID))
	{
		if (pHitBox)
		{
			// See if we really impacted on the box...

			if (pHitBox->DidProjectileImpact(this))
			{
				// This is the object that we really hit...

				hObj = pHitBox->GetModelObject();
			}
			else
			{
				return;
			}
		}
		else if (!(dwFlags & FLAG_RAYHIT))
		{
			// If we have ray hit set to true, projectiles should
			// impact on us too...

			return;
		}
	}


	// See if we hit the sky...

	if (bIsWorld || (OT_WORLDMODEL == g_pLTServer->GetObjectType(hObj)))
	{
		CollisionInfo info;
        g_pLTServer->GetLastCollision(&info);

		SurfaceType eType = GetSurfaceType(info);

		if (eType == ST_SKY)
		{
			RemoveObject();
			return;
		}
		else if (eType == ST_INVISIBLE)
		{
			// Update 1.002 [KLS] - If multiplayer and we hit an invisible
			// surface, just treat it like a normal surface...
			if (!IsMultiplayerGame())
			{
				m_bProcessInvImpact = LTTRUE;

				g_pLTServer->GetObjectPos(m_hObject, &m_vInvisNewPos);
				g_pLTServer->GetVelocity(m_hObject, &m_vInvisVel);
				m_vInvisNewPos += (m_vInvisVel * g_pLTServer->GetFrameTime());

				// Make sure this new position is inside the world...else
				// just blow up...

				if (LT_INSIDE == g_pLTServer->Common()->GetPointStatus(&m_vInvisNewPos))
				{
					return;
				}
			}
		}
	}


	HandleImpact(hObj);
}
void Body::Update()
{
	if ( !m_hObject ) return;

    LTVector vPos, vMin, vMax;
    g_pLTServer->GetWorldBox(vMin, vMax);
    g_pLTServer->GetObjectPos(m_hObject, &vPos);

	if (vPos.x < vMin.x || vPos.y < vMin.y || vPos.z < vMin.z ||
		vPos.x > vMax.x || vPos.y > vMax.y || vPos.z > vMax.z)
	{
		RemoveObject();
	}


	// Update the animator

	m_Animator.Update();

	// Make sure our hit box is in the correct position...

	UpdateHitBox();

	if ( m_bFirstUpdate )
	{
		m_bFirstUpdate = LTFALSE;
		m_fStartTime   = g_pLTServer->GetTime();
	}

	SetNextUpdate(s_fUpdateDelta);

	// We keep the body active to update dims for 2.0 seconds

	LTBOOL bUpdatingDims = g_pLTServer->GetTime() < m_fStartTime + 2.0f;

	// The deactivate-check, update, activate-check is ordered so that
	// deactivation will always happen one update after you enter a state,
	// but activation will always happen when you just entered the state.
	// This avoids a lot of issues with changing between active/inactive states.

	if ( !bUpdatingDims && (!m_pState || m_pState->CanDeactivate()) )
	{
		// Finalize the dims of our hit box...

		if (m_hHitBox)
		{
			CCharacterHitBox* pHitBox = (CCharacterHitBox*) g_pLTServer->HandleToObject(m_hHitBox);
			if ( pHitBox )
			{
				// For now just make the hit box 50% larger than our dims...

				LTVector vDims, vNewDims;
				g_pLTServer->GetObjectDims(m_hHitBox, &vDims);
				vNewDims = vDims;
				vNewDims.x *= 3.0f;
				vNewDims.z *= 3.0f;

				// Update 1.003, some cases the dims can get weird, not
				// sure why...Just make sure they are reasonable...
				if (vNewDims.x <= 0.0f || vNewDims.x > 75.0f)
				{
					vNewDims.x = 75.0f;
				}
				if (vNewDims.z <= 0.0f || vNewDims.z > 75.0f)
				{
					vNewDims.z = 75.0f;
				}

				// Only shrink us down if we're not sitting or stuck to a wall

				if ( m_eBodyStatePrevious == eBodyStateChair )
				{
				}
				else if ( m_eBodyStatePrevious == eBodyStateArrow )
				{
				}
				else
				{
					vNewDims.y = 15.0f;
				}

				g_pLTServer->SetObjectDims(m_hHitBox, &vNewDims);

				LTVector vOffset(0, vNewDims.y - vDims.y, 0);
				pHitBox->SetOffset(vOffset);
				pHitBox->Update();
			}
		}

		SetNextUpdate(0.0f);
	}

	if ( m_pState )
	{
		m_pState->Update();
	}

	if ( bUpdatingDims || (m_pState && !m_pState->CanDeactivate()) )
	{
	    SetNextUpdate(s_fUpdateDelta);
	}
}
示例#7
0
uint32 PickupItem::EngineMessageFn(uint32 messageID, void *pData, LTFLOAT fData)
{
	switch(messageID)
	{
		case MID_UPDATE:
		{
			Update();
		}
		break;

		case MID_TOUCHNOTIFY:
		{
			if( !m_bTouchPickup ) break;

			HOBJECT hObj = (HOBJECT)pData;

			// If this is a character hit box, use its object...

			CCharacterHitBox* pHitBox = LTNULL;
			if (IsCharacterHitBox(hObj))
			{
				pHitBox = (CCharacterHitBox*)g_pLTServer->HandleToObject(hObj);
				if (pHitBox)
				{
					hObj = pHitBox->GetModelObject();
				}
			}


			// If the object is dead, it can't pick up stuff...

			if (IsPlayer(hObj))
			{
                CPlayerObj* pPlayer = (CPlayerObj*)g_pLTServer->HandleToObject(hObj);

				if (!pPlayer || pPlayer->IsDead()) break;

				SetPlayerObj(hObj);
			}
			else
			{
                SetPlayerObj(LTNULL);
				break;
			}

			ObjectTouch(hObj);
		}
		break;

		case MID_PRECREATE:
		{
			ObjectCreateStruct* pInfo = (ObjectCreateStruct*)pData;
	
			if (fData == PRECREATE_WORLDFILE)
			{
				ReadProp(pInfo);
			}
			else if (fData == PRECREATE_STRINGPROP)
			{
				ReadProp(pInfo);

				// Show ourself...

				pInfo->m_Flags |= FLAG_VISIBLE;
			}

			PostPropRead(pInfo);
		}
		break;

		case MID_INITIALUPDATE:
		{
			if (fData != INITIALUPDATE_SAVEGAME)
			{
				InitialUpdate();
			}
		}
		break;

		case MID_SAVEOBJECT:
		{
            Save((ILTMessage_Write*)pData, (uint32)fData);
		}
		break;

		case MID_LOADOBJECT:
		{
            Load((ILTMessage_Read*)pData, (uint32)fData);
			
			uint32 dwRet = GameBase::EngineMessageFn(messageID, pData, fData);
			
			// We need to reset our sfx message since values
			// could have changed across save versions.

			CreateSpecialFX( );

			return dwRet;
		}
		break;

		default : break;
	}

	return GameBase::EngineMessageFn(messageID, pData, fData);
}
示例#8
0
void Prop::HandleTouch(HOBJECT hToucher)
{
	// Only characters can touch props.

	if( ( hToucher != LTNULL ) &&
		( !IsCharacter(hToucher) ) &&
		( !IsExplosion(hToucher) ) )
	{
		return;
	}

	if ( (m_eState == kState_PropDestroyed)
		|| (m_eState == kState_PropKnocked) 
		|| (!(m_pDisturb && m_pDisturb->pPD)) )
	{
		return;
	}

	// Resolve the toucher to a character handle.

	HOBJECT hCharacter = LTNULL;
	if( IsCharacterHitBox( hToucher ) )
	{
		CCharacterHitBox* pHB = (CCharacterHitBox*)g_pLTServer->HandleToObject(hToucher);
		hCharacter = pHB->GetModelObject();
	}
	else if( IsExplosion( hToucher ) )
	{
		Explosion* pExplosion = (Explosion*)g_pLTServer->HandleToObject(hToucher);
		hCharacter = pExplosion->GetFiredFrom();
	}
	else if( IsCharacter( hToucher ) ) 
	{
		hCharacter = hToucher;
	}


	// Only players can touch (for now).
	if((hCharacter != LTNULL) && !IsPlayer(hCharacter)) return;

	if(m_eState == kState_PropTouching)
	{
		// Clear sound if done playing.

		ClearTouchSoundIfDone(LTFALSE);

		// Check if both sound and animation are done, or just the sound for a "knock."

		if( m_pDisturb->hTouchSound == LTNULL )
		{
			switch( m_pDisturb->eTouchAnimType )
			{
				// Touch animations reset.

				case kPA_Touch:
					ClearTouchAnimIfDone(m_pDisturb->hTouchAnim, LTFALSE);
					if( g_pLTServer->GetModelAnimation(m_hObject) != m_pDisturb->hTouchAnim )
					{
						m_eState = kState_PropDefault;
						return;
					}
					break;

				// Knock animations remain on the last frame forever.

				case kPA_Knock:
					if( MS_PLAYDONE & g_pLTServer->GetModelPlaybackState(m_hObject) )
					{
						m_bTouchable = LTFALSE;

						g_pCommonLT->SetObjectFlags(m_hObject, OFT_User, 0, USRFLG_CAN_ACTIVATE);

						m_eState = kState_PropKnocked;
						return;
					}
					break;
			}
		}
	}


	// Play the touch sound and animation.

	if( (m_eState == kState_PropDefault) && (hCharacter != LTNULL))
	{
        LTVector vPos;
		g_pLTServer->GetObjectPos(m_hObject, &vPos);

		// Play sound.
		PlayTouchSound(vPos);

		// Play animation.
		if(m_pDisturb->hTouchAnim != INVALID_ANI)
		{
			g_pLTServer->SetModelAnimation(m_hObject, m_pDisturb->hTouchAnim);
			g_pLTServer->SetModelLooping(m_hObject, LTFALSE);
			g_pLTServer->ResetModelAnimation(m_hObject);
		}

		// Register touch disturbance stimulus.

		if( (m_pDisturb->pPD->nTouchAlarmLevel > 0) && (m_pDisturb->pPD->fStimRadius > 0.f) )
		{
			g_pAIStimulusMgr->RegisterStimulus( kStim_EnemyDisturbanceSound, m_pDisturb->pPD->nTouchAlarmLevel, hCharacter, m_hObject, vPos, m_pDisturb->pPD->fStimRadius );

			// Props that are knocked over have a visual stimulus too.

			if( m_pDisturb->eTouchAnimType == kPA_Knock )
			{
				g_pAIStimulusMgr->RegisterStimulus( kStim_EnemyDisturbanceVisible, m_pDisturb->pPD->nTouchAlarmLevel + 1, hCharacter, m_hObject, vPos, m_pDisturb->pPD->fStimRadius );
			}
		}

		m_eState = kState_PropTouching;
	}

	// Update while playing touch sound and/or animation.
	SetNextUpdate(UPDATE_NEXT_FRAME);
}
示例#9
0
uint32 Prop::EngineMessageFn(uint32 messageID, void *pData, LTFLOAT fData)
{
	switch(messageID)
	{
		case MID_TOUCHNOTIFY:
		{
			if(m_bTouchable)
			{
				HOBJECT hToucher = (HOBJECT)pData;
				if( IsCharacterHitBox( hToucher ) )
				{
					CCharacterHitBox* pHB = (CCharacterHitBox*)g_pLTServer->HandleToObject(hToucher);
					hToucher = pHB->GetModelObject();
				}

				// Could be a body.
				if( IsCharacter(hToucher) )
				{
					HandleTouch( hToucher );
				}
			}
			else if( m_bAttachmentShotOff )
			{
				HandleAttachmentTouch( (HOBJECT)pData );
			}
		}
		break;

		case MID_UPDATE:
		{
			Update();
		}
		break;

		case MID_MODELSTRINGKEY :
		{
			HandleModelString( (ArgList*)pData );
		}
		break;

		case MID_PRECREATE:
		{
			if (fData == PRECREATE_WORLDFILE || fData == PRECREATE_STRINGPROP)
			{
				ObjectCreateStruct* pStruct = (ObjectCreateStruct*)pData;
				ReadProp(pStruct);

				// If this prop is spawned, assume it should be visible (if they
				// specify Visible 0, our parent class will handle it ;)

				if (fData == PRECREATE_STRINGPROP)
				{
					m_dwFlags |= FLAG_VISIBLE;
				}
			}

			// We must remove aggregates before sending the message to the base classs...

			if( !m_bCanTransition )
			{
				// Disallow transitioning of this object through TransAMs...

				DestroyTransitionAggregate();
			}

            uint32 dwRet = GameBase::EngineMessageFn(messageID, pData, fData);

			PostPropRead((ObjectCreateStruct*)pData);
			return dwRet;
		}
		break;

		case MID_INITIALUPDATE:
		{
			if (fData != INITIALUPDATE_SAVEGAME)
			{
				InitialUpdate();
			}
		}
		break;

		case MID_SAVEOBJECT:
		{
            Save((ILTMessage_Write*)pData, (uint32)fData);
		}
		break;

		case MID_LOADOBJECT:
		{
            Load((ILTMessage_Read*)pData, (uint32)fData);
		}
		break;

		default : break;
	}


	return GameBase::EngineMessageFn(messageID, pData, fData);
}
示例#10
0
void Prop::HandleHit( HOBJECT hDamager )
{
	if( ( hDamager != LTNULL ) &&
		( !IsCharacter(hDamager) ) &&
		( !IsExplosion(hDamager) ) )
	{
		return;
	}

	if( (m_eState == kState_PropDestroyed)
		|| (m_eState == kState_PropKnocked) 
		|| (!(m_pDisturb && m_pDisturb->pPD)) )
	{
		return;
	}

	// If we don't have a valid hit animation default to the touch animation...

	if( m_pDisturb->hHitAnim == INVALID_ANI )
		HandleTouch( hDamager );

	// Resolve the toucher to a character handle.

	HOBJECT hCharacter = LTNULL;
	if( IsCharacterHitBox( hDamager ) )
	{
		CCharacterHitBox* pHB = (CCharacterHitBox*)g_pLTServer->HandleToObject(hDamager);
		hCharacter = pHB->GetModelObject();
	}
	else if( IsExplosion( hDamager ) )
	{
		Explosion* pExplosion = (Explosion*)g_pLTServer->HandleToObject(hDamager);
		hCharacter = pExplosion->GetFiredFrom();
	}
	else if( IsCharacter( hDamager ) ) 
	{
		hCharacter = hDamager;
	}

	// Only characters can hit (for now).
	if((hCharacter != LTNULL) && !IsCharacter(hCharacter)) return;

	if(m_eState == kState_PropHit)
	{
		// Check if both sound and animation are done

		ClearHitSoundIfDone( LTFALSE );
		if( m_pDisturb->hHitSound == LTNULL )
		{
			ClearHitAnimIfDone( LTFALSE );
			if( g_pLTServer->GetModelAnimation(m_hObject) != m_pDisturb->hHitAnim )
			{
				m_eState = kState_PropDefault;
				return;
			}
		}
	}
	
	// Play the hit sound and animation.

	if( (m_eState == kState_PropDefault) && (hCharacter != LTNULL))
	{
        LTVector vPos;
		g_pLTServer->GetObjectPos(m_hObject, &vPos);

		// Play sound.
		PlayHitSound(vPos);

		// Play animation.
		if(m_pDisturb->hHitAnim != INVALID_ANI)
		{
			g_pLTServer->SetModelAnimation( m_hObject, m_pDisturb->hHitAnim );
			g_pLTServer->SetModelLooping( m_hObject, LTFALSE );
			g_pLTServer->ResetModelAnimation(m_hObject);
		}

		// Register touch disturbance stimulus.

		if( (m_pDisturb->pPD->nHitAlarmLevel > 0) && (m_pDisturb->pPD->fStimRadius > 0.f) )
		{
			g_pAIStimulusMgr->RegisterStimulus( kStim_EnemyDisturbanceSound, m_pDisturb->pPD->nHitAlarmLevel, hCharacter, m_hObject, vPos, m_pDisturb->pPD->fStimRadius );
		}

		m_eState = kState_PropHit;
	}

	// Update while playing touch sound and/or animation.
	SetNextUpdate(UPDATE_NEXT_FRAME);
}