2
0
mirror of https://github.com/FWGS/hlsdk-xash3d synced 2024-11-22 18:05:23 +01:00
hlsdk-xash3d/dlls/monsterstate.cpp

234 lines
6.4 KiB
C++
Raw Normal View History

2016-06-04 15:24:23 +02:00
/***
*
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* This source code contains proprietary and confidential information of
* Valve LLC and its suppliers. Access to this code is restricted to
* persons who have executed a written SDK license with Valve. Any access,
* use or distribution of this code by or to any unlicensed person is illegal.
*
****/
//=========================================================
// monsterstate.cpp - base class monster functions for
// controlling core AI.
//=========================================================
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "nodes.h"
#include "monsters.h"
#include "animation.h"
#include "saverestore.h"
#include "soundent.h"
//=========================================================
// SetState
//=========================================================
2016-07-31 15:48:50 +02:00
void CBaseMonster::SetState( MONSTERSTATE State )
2016-06-04 15:24:23 +02:00
{
/*
2016-07-31 15:48:50 +02:00
if( State != m_MonsterState )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
ALERT( at_aiconsole, "State Changed to %d\n", State );
2016-06-04 15:24:23 +02:00
}
*/
switch( State )
{
2016-06-04 15:24:23 +02:00
// Drop enemy pointers when going to idle
case MONSTERSTATE_IDLE:
2017-06-29 15:56:03 +02:00
if( m_hEnemy != 0 )
2016-06-04 15:24:23 +02:00
{
m_hEnemy = NULL;// not allowed to have an enemy anymore.
2016-07-31 15:48:50 +02:00
ALERT( at_aiconsole, "Stripped\n" );
2016-06-04 15:24:23 +02:00
}
break;
2016-06-13 16:29:45 +02:00
default:
break;
2016-06-04 15:24:23 +02:00
}
m_MonsterState = State;
m_IdealMonsterState = State;
}
//=========================================================
// RunAI
//=========================================================
2016-07-31 15:48:50 +02:00
void CBaseMonster::RunAI( void )
2016-06-04 15:24:23 +02:00
{
// to test model's eye height
//UTIL_ParticleEffect ( pev->origin + pev->view_ofs, g_vecZero, 255, 10 );
// IDLE sound permitted in ALERT state is because monsters were silent in ALERT state. Only play IDLE sound in IDLE state
// once we have sounds for that state.
2020-12-25 07:14:22 +01:00
if( ( m_MonsterState == MONSTERSTATE_IDLE || m_MonsterState == MONSTERSTATE_ALERT ) && RANDOM_LONG( 0, 99 ) == 0 && !( pev->spawnflags & SF_MONSTER_GAG ) )
2016-06-04 15:24:23 +02:00
{
IdleSound();
}
2016-07-31 15:48:50 +02:00
if( m_MonsterState != MONSTERSTATE_NONE &&
m_MonsterState != MONSTERSTATE_PRONE &&
2016-06-04 15:24:23 +02:00
m_MonsterState != MONSTERSTATE_DEAD )// don't bother with this crap if monster is prone.
{
// collect some sensory Condition information.
// don't let monsters outside of the player's PVS act up, or most of the interesting
// things will happen before the player gets there!
// UPDATE: We now let COMBAT state monsters think and act fully outside of player PVS. This allows the player to leave
// an area where monsters are fighting, and the fight will continue.
2016-07-31 15:48:50 +02:00
if( !FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) || ( m_MonsterState == MONSTERSTATE_COMBAT ) )
2016-06-04 15:24:23 +02:00
{
Look( m_flDistLook );
Listen();// check for audible sounds.
// now filter conditions.
ClearConditions( IgnoreConditions() );
GetEnemy();
}
// do these calculations if monster has an enemy.
2017-06-29 15:56:03 +02:00
if( m_hEnemy != 0 )
2016-06-04 15:24:23 +02:00
{
CheckEnemy( m_hEnemy );
}
CheckAmmo();
}
FCheckAITrigger();
PrescheduleThink();
MaintainSchedule();
// if the monster didn't use these conditions during the above call to MaintainSchedule() or CheckAITrigger()
// we throw them out cause we don't want them sitting around through the lifespan of a schedule
// that doesn't use them.
m_afConditions &= ~( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE );
}
//=========================================================
// GetIdealState - surveys the Conditions information available
// and finds the best new state for a monster.
//=========================================================
2016-07-31 15:48:50 +02:00
MONSTERSTATE CBaseMonster::GetIdealState( void )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
int iConditions;
2016-06-04 15:24:23 +02:00
iConditions = IScheduleFlags();
2016-07-31 15:48:50 +02:00
2016-06-04 15:24:23 +02:00
// If no schedule conditions, the new ideal state is probably the reason we're in here.
2016-07-31 15:48:50 +02:00
switch( m_MonsterState )
2016-06-04 15:24:23 +02:00
{
case MONSTERSTATE_IDLE:
/*
IDLE goes to ALERT upon hearing a sound
-IDLE goes to ALERT upon being injured
IDLE goes to ALERT upon seeing food
-IDLE goes to COMBAT upon sighting an enemy
IDLE goes to HUNT upon smelling food
*/
{
2016-07-31 15:48:50 +02:00
if( iConditions & bits_COND_NEW_ENEMY )
2016-06-04 15:24:23 +02:00
{
// new enemy! This means an idle monster has seen someone it dislikes, or
// that a monster in combat has found a more suitable target to attack
m_IdealMonsterState = MONSTERSTATE_COMBAT;
}
2016-07-31 15:48:50 +02:00
else if( iConditions & bits_COND_LIGHT_DAMAGE )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
MakeIdealYaw( m_vecEnemyLKP );
2016-06-04 15:24:23 +02:00
m_IdealMonsterState = MONSTERSTATE_ALERT;
}
2016-07-31 15:48:50 +02:00
else if( iConditions & bits_COND_HEAVY_DAMAGE )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
MakeIdealYaw( m_vecEnemyLKP );
2016-06-04 15:24:23 +02:00
m_IdealMonsterState = MONSTERSTATE_ALERT;
}
2016-07-31 15:48:50 +02:00
else if( iConditions & bits_COND_HEAR_SOUND )
2016-06-04 15:24:23 +02:00
{
CSound *pSound;
2016-07-31 15:48:50 +02:00
2016-06-04 15:24:23 +02:00
pSound = PBestSound();
ASSERT( pSound != NULL );
2016-07-31 15:48:50 +02:00
if( pSound )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
MakeIdealYaw( pSound->m_vecOrigin );
if( pSound->m_iType & ( bits_SOUND_COMBAT|bits_SOUND_DANGER ) )
2016-06-04 15:24:23 +02:00
m_IdealMonsterState = MONSTERSTATE_ALERT;
}
}
2016-07-31 15:48:50 +02:00
else if( iConditions & ( bits_COND_SMELL | bits_COND_SMELL_FOOD ) )
2016-06-04 15:24:23 +02:00
{
m_IdealMonsterState = MONSTERSTATE_ALERT;
}
break;
}
case MONSTERSTATE_ALERT:
/*
ALERT goes to IDLE upon becoming bored
-ALERT goes to COMBAT upon sighting an enemy
ALERT goes to HUNT upon hearing a noise
*/
{
2016-07-31 15:48:50 +02:00
if( iConditions & ( bits_COND_NEW_ENEMY | bits_COND_SEE_ENEMY ) )
2016-06-04 15:24:23 +02:00
{
// see an enemy we MUST attack
m_IdealMonsterState = MONSTERSTATE_COMBAT;
}
2016-07-31 15:48:50 +02:00
else if( iConditions & bits_COND_HEAR_SOUND )
2016-06-04 15:24:23 +02:00
{
m_IdealMonsterState = MONSTERSTATE_ALERT;
CSound *pSound = PBestSound();
ASSERT( pSound != NULL );
2016-07-31 15:48:50 +02:00
if( pSound )
MakeIdealYaw( pSound->m_vecOrigin );
2016-06-04 15:24:23 +02:00
}
break;
}
case MONSTERSTATE_COMBAT:
/*
COMBAT goes to HUNT upon losing sight of enemy
COMBAT goes to ALERT upon death of enemy
*/
{
2017-06-29 15:56:03 +02:00
if( m_hEnemy == 0 )
2016-06-04 15:24:23 +02:00
{
m_IdealMonsterState = MONSTERSTATE_ALERT;
// pev->effects = EF_BRIGHTFIELD;
2016-07-31 15:48:50 +02:00
ALERT( at_aiconsole, "***Combat state with no enemy!\n" );
2016-06-04 15:24:23 +02:00
}
break;
}
case MONSTERSTATE_HUNT:
/*
HUNT goes to ALERT upon seeing food
HUNT goes to ALERT upon being injured
HUNT goes to IDLE if goal touched
HUNT goes to COMBAT upon seeing enemy
*/
{
break;
}
case MONSTERSTATE_SCRIPT:
2016-07-31 15:48:50 +02:00
if( iConditions & ( bits_COND_TASK_FAILED | bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ) )
2016-06-04 15:24:23 +02:00
{
ExitScriptedSequence(); // This will set the ideal state
}
break;
case MONSTERSTATE_DEAD:
m_IdealMonsterState = MONSTERSTATE_DEAD;
break;
2016-06-13 16:29:45 +02:00
default:
break;
2016-06-04 15:24:23 +02:00
}
return m_IdealMonsterState;
}