예제 #1
0
//----------------------------------------------------------------------------
//              
//	ROUTINE:	CAIHumanStateResurrecting::Init()
//              
//	PURPOSE:	
//              
//----------------------------------------------------------------------------
/*virtual*/ LTBOOL CAIHumanStateResurrecting::Init(CAIHuman* pAIHuman)
{
	if ( !CAIHumanState::Init(pAIHuman) )
	{
		return LTFALSE;
	}

	// Set the time tracking vars to invalid times
	m_fResurrectCompleteTime = -1;
	m_fResurrectCompleteDuration = -1;

	GetAI()->SetBlinking(LTFALSE);

	m_eStateStatus = kSStat_Resurrecting;

	CDestructible* pDestructable = GetAI()->GetDestructible();
	m_bEntryCanDistruct = pDestructable->GetNeverDestroy();
	pDestructable->SetNeverDestroy( LTFALSE );
	pDestructable->SetHitPoints( pDestructable->GetMaxHitPoints() );

	// Ensure that node tracking is disabled.
	m_pAIHuman->DisableNodeTracking();

	return LTTRUE;
}
예제 #2
0
bool CAISensorDamageFX::StimulateSensor( CAIStimulusRecord* pStimulusRecord )
{
	// Intentionally do not call super::StimulateSensor.
	// Just monitor the AI's health and create FX.  Do not affect WorkingMemory.

	// Bail if the wrong type of stimulus.

	if( !( m_pSensorRecord->dwStimulusTypes & pStimulusRecord->m_eStimulusType ) )
	{
		return false;
	}

	// Sanity check.
	
	CDestructible* pDestructible = m_pAI->GetDestructible();
	if( ( m_fFullHealth <= 0.f ) || ( !pDestructible ) )
	{
		return false;
	}

	// Create damage FX based on the percentage of remaining health.

	float fHealthPercent = pDestructible->GetHitPoints() / m_fFullHealth;
	switch( m_eDamageFXState )
	{
		case kDamageFX_None:
			if( fHealthPercent < 0.75f )
			{
				m_eDamageFXState = kDamageFX_75;
				CreateDamageFX( kDamageFX_75 );
			}
			break;

		case kDamageFX_75:
			if( fHealthPercent < 0.5f )
			{
				m_eDamageFXState = kDamageFX_50;
				CreateDamageFX( kDamageFX_None );
				CreateDamageFX( kDamageFX_50 );
			}
			break;

		case kDamageFX_50:
			if( fHealthPercent < 0.25f )
			{
				m_eDamageFXState = kDamageFX_25;
				CreateDamageFX( kDamageFX_None );
				CreateDamageFX( kDamageFX_25 );
			}
			break;
	}

	// Always return false, to let other sensors handle damage.

	return false;
}
예제 #3
0
//----------------------------------------------------------------------------
//              
//	ROUTINE:	CAIHumanStateResurrecting::~CAIHumanStateResurrecting()
//              
//	PURPOSE:	
//              
//----------------------------------------------------------------------------
/*virtual*/ CAIHumanStateResurrecting::~CAIHumanStateResurrecting()
{
	// Destruct
	if ( GetAI() && !GetAI()->IsDead() )
	{
		CDestructible* pDestructable = GetAI()->GetDestructible();
		pDestructable->SetNeverDestroy( m_bEntryCanDistruct );
		pDestructable->SetHitPoints( pDestructable->GetMaxHitPoints() );
	}
}
bool CAISensorEnemyDamagedSuicide::UpdateSensor()
{
	if( !super::UpdateSensor() )
	{
		return false;
	}

	// AI is not targeting anyone.

	if( !m_pAI->HasTarget( kTarget_Character ) )
	{
		return false;
	}

	// Bail if no target.

	HOBJECT hTarget = m_pAI->GetAIBlackBoard()->GetBBTargetObject();
	CCharacter* pChar = (CCharacter*)g_pLTServer->HandleToObject( hTarget );
	if( !pChar )
	{
		return false;
	}

	// Bail if no destructible.

	CDestructible* pDestructible = pChar->GetDestructible();
	if( !pDestructible )
	{
		return false;
	}

	// Bail if we were not the last damager.

	if( pDestructible->GetLastDamager() != m_pAI->m_hObject )
	{
		return false;
	}

	// No new damage.

	if( pDestructible->GetLastDamageTime() <= 0.f )
	{
		return false;
	}

	// We damaged the target.
	// So kill myself.
	
	g_pCmdMgr->QueueMessage( m_pAI, m_pAI, "DESTROY" );

	return true;
}
예제 #5
0
// ----------------------------------------------------------------------- //
//
//	ROUTINE:	CoreDump::HandleComplete
//
//	PURPOSE:	Transfer the inventory/energy to the player
//
// ----------------------------------------------------------------------- //
void CoreDump::HandleComplete(HOBJECT hSender)
{
	if(!IsPlayer(hSender))
	{
		g_pLTServer->CPrint("ERROR - CoreDump received a complete message from an object other than a player!\n");
		ASSERT(FALSE);
		return;
	}

	// Invoke the inventory commands
	int i;
	char *szCmd;
	GEN_INVENTORY_LIST::iterator iter;
	for(iter=m_lstInventory.begin();iter!=m_lstInventory.end();iter++)
	{
		// First get the command
		szCmd = g_pInventoryButeMgr->GetItemCommand(iter->nItemID);
		for(i=0;i<iter->nCount;i++)
		{
			// Now process it N times (once for each instance of the item we have)
			if(g_pCmdMgr->IsValidCmd(szCmd))
			{
				g_pCmdMgr->Process(szCmd,m_hObject,NULL);
			}
		}
	}

	// Now give the player some energy
	CTronPlayerObj* pPlayer = (CTronPlayerObj*) g_pLTServer->HandleToObject(hSender);
	
	// Get the player's damage aggregage
	CDestructible* pDest = m_pPlayer->GetDestructible();
	ASSERT(pDest);
	int nMax = (int)pDest->GetMaxEnergy();
	int nNew = (int)m_fCurrentEnergy + (int)pDest->GetEnergy();

	// Check
	if(nNew <= nMax)
	{
		// And set
		pDest->SetEnergy((float)nNew);
	}

	// And we're done.
	Term();
}
예제 #6
0
void Body::Init(const BODYINITSTRUCT& bi)
{
	if (!bi.pCharacter || !bi.pCharacter->m_hObject) return;

	// Get the death type etc

	m_eDeathType		= bi.pCharacter->GetDeathType();
	m_eModelId			= bi.pCharacter->GetModelId();
	m_eModelSkeleton    = bi.pCharacter->GetModelSkeleton();
	m_eModelStyle		= bi.pCharacter->GetModelStyle();

	// Get the body lifetime

	m_fLifetime		= bi.fLifetime;

	// Create the SFX

	BODYCREATESTRUCT bcs;
	bcs.eBodyState = bi.eBodyState;
	if (IsPlayer(bi.pCharacter->m_hObject))
	{
		CPlayerObj* pPlayer = (CPlayerObj*) bi.pCharacter;
		bcs.nClientId = (uint8) g_pLTServer->GetClientID(pPlayer->GetClient());
	}

    HMESSAGEWRITE hMessage = g_pLTServer->StartSpecialEffectMessage(this);
    g_pLTServer->WriteToMessageByte(hMessage, SFX_BODY_ID);
    bcs.Write(g_pLTServer, hMessage);
    g_pLTServer->EndMessage(hMessage);


	// Create the death scene

	CreateDeathScene(bi.pCharacter);

	// We'll handle creating the necessary debris...

	m_damage.m_bCreatedDebris = LTTRUE;

	m_damage.SetCanDamage(LTFALSE);//bi.pCharacter->CanDamageBody());
	m_damage.SetApplyDamagePhysics(LTFALSE);//bi.pCharacter->CanDamageBody());
	m_damage.SetMass(g_pModelButeMgr->GetModelMass(m_eModelId));

	// Let us get hit by decay powder

	m_damage.ClearCantDamageTypes(DamageTypeToFlag(DT_GADGET_DECAYPOWDER));

	switch ( g_pModelButeMgr->GetModelType(m_eModelId) )
	{
		case eModelTypeVehicle:
		{
			m_eDeathType = CD_GIB;
		}
		break;
	}

	CDestructible* pDest = bi.pCharacter->GetDestructible();
	if (pDest)
	{
		m_eDamageType = pDest->GetDeathType();
		VEC_COPY(m_vDeathDir, pDest->GetDeathDir());
		VEC_NORM(m_vDeathDir);
		VEC_MULSCALAR(m_vDeathDir, m_vDeathDir, 1.0f + (pDest->GetDeathDamage() / pDest->GetMaxHitPoints()));
	}

	LTFLOAT fHitPts = pDest->GetMaxHitPoints();
	m_damage.Reset(fHitPts, 0.0f);
	m_damage.SetHitPoints(fHitPts);
	m_damage.SetMaxHitPoints(fHitPts);
	m_damage.SetArmorPoints(0.0f);
	m_damage.SetMaxArmorPoints(0.0f);

	// Copy our user flags over, setting our surface type to flesh

    uint32 dwUsrFlags = g_pLTServer->GetObjectUserFlags(m_hObject) | USRFLG_NIGHT_INFRARED;
	dwUsrFlags |= SurfaceToUserFlag(ST_FLESH);
    g_pLTServer->SetObjectUserFlags(m_hObject, dwUsrFlags);

	// Make sure model doesn't slide all over the place...

    g_pLTServer->SetFrictionCoefficient(m_hObject, 500.0f);

	LTVector vDims;
    g_pLTServer->GetObjectDims(bi.pCharacter->m_hObject, &vDims);

	// Set the dims.  If we can't set the dims that big, set them
	// as big as possible...

    if (g_pLTServer->SetObjectDims2(m_hObject, &vDims) == LT_ERROR)
	{
        g_pLTServer->SetObjectDims2(m_hObject, &vDims);
	}


	// Create the box used for weapon impact detection...

	CreateHitBox(bi);


	LTFLOAT r, g, b, a;
    g_pLTServer->GetObjectColor(bi.pCharacter->m_hObject, &r, &g, &b, &a);
    g_pLTServer->SetObjectColor(m_hObject, r, g, b, a);

	LTVector vScale;
    g_pLTServer->GetObjectScale(bi.pCharacter->m_hObject, &vScale);
    g_pLTServer->ScaleObject(m_hObject, &vScale);

	// Copy our animation over

    HMODELANIM hAni = g_pLTServer->GetModelAnimation(bi.pCharacter->m_hObject);
    g_pLTServer->SetModelAnimation(m_hObject, hAni);
    g_pLTServer->SetModelLooping(m_hObject, LTFALSE);

	// Copy the flags from the character to us

	uint32 dwFlags = g_pLTServer->GetObjectFlags(bi.pCharacter->m_hObject);
	m_dwFlags |= FLAG_REMOVEIFOUTSIDE;
    g_pLTServer->SetObjectFlags(m_hObject, dwFlags);

	// Move the attachments aggregate from the char to us...

	if (!m_pAttachments && bi.eBodyState != eBodyStateLaser)
	{
		m_hWeaponItem = bi.pCharacter->TransferWeapon(m_hObject);

		// Make sure we're playing the correct ani...

		if (m_hWeaponItem)
		{
			uint32 dwAni = g_pLTServer->GetAnimIndex(m_hWeaponItem, "Hand");
		 	if (dwAni != INVALID_ANI)
			{
				g_pLTServer->SetModelAnimation(m_hWeaponItem, dwAni);
				g_pLTServer->SetModelLooping(m_hWeaponItem, LTFALSE);
			}
		}
	}

	if (!m_pAttachments)
	{
		m_pAttachments = bi.pCharacter->TransferAttachments();

		if (m_pAttachments)
		{
			AddAggregate(m_pAttachments);
			m_pAttachments->ReInit(m_hObject);
		}
	}

	// Set up the spears

	bi.pCharacter->TransferSpears(this);

	// Set our state

	SetState(bi.eBodyState);
}
예제 #7
0
bool CAISensorInstantDeath::UpdateSensor()
{
	if( !super::UpdateSensor() )
	{
		return false;
	}

	// This sensor is somewhat of a hack.  It was added because the AIActionInstantDeath
	// runs a couple frames too late to catch all situations where we would like AI to 
	// die instantly.  Ideally, we would refactor the way we handle damage to allow 
	// more immediate planner reaction.

	// This sensor is irrelevant once the AI has targeted something.

	if( m_pAI->GetAIBlackBoard()->GetBBTargetType() != kTarget_None )
	{
		m_pAI->GetAISensorMgr()->RemoveAISensor( kSensor_InstantDeath );
		return false;
	}

	// Sanity check.

	CDestructible *pDestructible = m_pAI->GetDestructible();
	if( !pDestructible )
	{
		return false;
	}

	// No new damage.

	if( pDestructible->GetLastDamageTime() == 0.f )
	{
		return false;
	}

	// This sensor is irrelevant after the first time we have been damaged.

	m_pAI->GetAISensorMgr()->RemoveAISensor( kSensor_InstantDeath );

	// Don't die instantly if NeverDestroy is set.

	if( pDestructible->GetNeverDestroy() )
	{
		return false;
	}

	// AI cannot take damage.

	if ( !m_pAI->GetDestructible()->GetCanDamage() )
	{
		return false;
	}

	// AI does not accept this type of damage.

	DamageStruct Damage = m_pAI->GetAIBlackBoard()->GetBBLastDamage();
	if( pDestructible->IsCantDamageType( Damage.eType ) )
	{
		return false;
	}

	// Die instantly if taken by surprise and hit in the head or torso.

	if( m_pAI->GetAIBlackBoard()->GetBBTargetType() == kTarget_None )
	{
		// Determine which body part was hit.

		ModelsDB::HNODE hModelNode = m_pAI->GetModelNodeLastHit();
		if( hModelNode )
		{
			EnumAnimProp eBodyAnipProp = g_pModelsDB->GetNodeBodyAnimProp( hModelNode );
			if( ( eBodyAnipProp == kAP_BODY_Head ) ||
				( eBodyAnipProp == kAP_BODY_Torso ) )
			{
				// Die instantly!  Use the data from the last damage received -- just 
				// lower the AI's hitpoints to less than 1.  This will insure this action behaves 
				// exactly like a standard death without any additional prompting.

				pDestructible->SetHitPoints( 0.1f );
				pDestructible->SetArmorPoints( 0.0f );
				Damage.fDamage = 2.0f;
				Damage.DoDamage( m_pAI->m_hObject, m_pAI->m_hObject );

				// Die silently.

				m_pAI->SetLastPainVolume( 0.1f );
				return true;
			}
		}
	}

	// Always allow other sensors to update.

	return false;
}