?? actor.cpp
字號(hào):
ent = targetList.ObjectAt( i );
if ( ent )
{
if ( ent->flags & (FL_CLOAK|FL_STEALTH) )
continue;
if ( !ent->deadflag && Hates( ent ) && !IsEnemy( ent ) )
{
MakeEnemy( ent );
}
else if ( ent->isSubclassOf( Actor ) && Likes( ent ) )
{
act = ( Actor * )ent;
if ( act->currentEnemy && Hates( act->currentEnemy ) && !IsEnemy( act->currentEnemy ) )
{
MakeEnemy( act->currentEnemy );
if ( act->deadflag )
{
//
// we have passed on the post mortem message of our death, so let's clear it
//
act->ClearEnemies();
}
}
}
}
}
}
newtarget = BestTarget();
if ( newtarget && ( newtarget != currentEnemy ) )
{
seenEnemy = false;
currentEnemy = newtarget;
if ( DoAction( "sightenemy" ) )
{
seenEnemy = true;
Chatter( "snd_sightenemy", 5 );
}
else
{
currentEnemy = NULL;
}
}
}
Entity *Actor::BestTarget
(
void
)
{
int i;
int n;
Entity *ent;
Entity *bestent;
float bestscore;
float score;
bestscore = 8192 * 8192 * 20;
n = enemyList.NumObjects();
if ( n == 1 )
{
// don't waste our time when we only have one enemy
return enemyList.ObjectAt( 1 );
}
bestent = NULL;
for( i = 1; i <= n; i++ )
{
ent = enemyList.ObjectAt( i );
if ( !ent || ent->deadflag )
{
enemyList.RemoveObjectAt( i );
i--;
n--;
continue;
}
score = Range( ent ) + 1;
if ( ent->health < WEAK_HEALTH )
{
// Try to kill off really weak enemies
score *= WEAK_WEIGHT;
}
if ( ent->health > health )
{
score *= STRONGER_WEIGHT;
}
if ( CanSeeFOV( ent ) )
{
// We're more interested in guys we can see
score *= VISIBLE_WEIGHT;
}
if ( i == n )
{
// Favor the latest enemy
score *= NEWENEMY_WEIGHT;
}
if ( score < bestscore )
{
bestscore = score;
bestent = ent;
}
}
return bestent;
}
Sentient *Actor::NearFriend
(
void
)
{
int i;
int num;
Entity *ent;
num = nearbyList.NumObjects();
for( i = 1; i < num; i++ )
{
ent = nearbyList.ObjectAt( i );
if ( Likes( ent ) )
{
return ( Sentient * )ent;
}
}
return NULL;
}
qboolean Actor::CloseToEnemy
(
Vector pos,
float howclose
)
{
Entity *ent;
int i;
int n;
n = enemyList.NumObjects();
for( i = 1; i <= n; i++ )
{
ent = enemyList.ObjectAt( i );
if ( !ent || ent->deadflag || ( ent->flags & FL_NOTARGET ) )
{
continue;
}
if ( WithinDistance( ent, howclose ) )
{
return true;
}
}
return false;
}
void Actor::EyeOffset
(
Event *ev
)
{
eyeposition -= eyeoffset;
eyeoffset = ev->GetVector( 1 );
eyeposition += eyeoffset;
}
//***********************************************************************************************
//
// State control functions
//
//***********************************************************************************************
void Actor::EnableState
(
str action
)
{
StateInfo *ptr;
ptr = GetState( action );
if ( ptr )
{
ptr->ignore = false;
}
}
void Actor::DisableState
(
str action
)
{
StateInfo *ptr;
ptr = GetState( action );
if ( ptr )
{
ptr->ignore = true;
}
}
StateInfo *Actor::SetResponse
(
str action,
str response,
qboolean ignore
)
{
StateInfo *ptr;
ptr = GetState( action );
if ( !ptr )
{
ptr = new StateInfo;
actionList.AddObject( ptr );
ptr->action = action;
}
ptr->response = response;
ptr->ignore = ignore;
return ptr;
}
const char *Actor::GetResponse
(
str action,
qboolean force
)
{
StateInfo *ptr;
ptr = GetState( action );
if ( ptr && ( force || !ptr->ignore ) )
{
return ptr->response.c_str();
}
return "";
}
StateInfo *Actor::GetState
(
str action
)
{
int i;
int n;
StateInfo *ptr;
n = actionList.NumObjects();
for( i = 1; i <= n; i++ )
{
ptr = actionList.ObjectAt( i );
if ( ptr->action == action )
{
return ptr;
}
}
return NULL;
}
//***********************************************************************************************
//
// State stack management
//
//***********************************************************************************************
void Actor::ClearStateStack
(
void
)
{
ActorState *state;
int n;
int i;
while( !stateStack.Empty() )
{
state = stateStack.Pop();
if ( state->animDoneEvent )
{
delete state->animDoneEvent;
}
// delete the old action/response list
n = state->actionList.NumObjects();
for( i = n; i >= 1; i-- )
{
delete state->actionList.ObjectAt( i );
}
state->actionList.ClearObjectList();
if ( state->behavior )
{
delete state->behavior;
}
if ( state->path )
{
delete state->path;
}
delete state;
}
numonstack = 0;
}
qboolean Actor::PopState
(
void
)
{
ActorState *newstate;
int n;
int i;
#ifdef DEBUG_PRINT
gi.dprintf( "%d Pop:", numonstack );
#endif
if ( !stateStack.Empty() )
{
newstate = stateStack.Pop();
numonstack--;
state = newstate->name;
#ifdef DEBUG_PRINT
gi.dprintf( "state '%s' anim '%s'", state.c_str(), newstate->anim.c_str() );
#endif
if ( newstate->anim.length() )
{
SetAnim( newstate->anim, newstate->animDoneEvent );
ChangeAnim();
}
SetPath( newstate->path );
#ifdef DEBUG_PRINT
if ( newstate->behavior )
{
gi.dprintf( "%s", newstate->behavior->getClassname() );
}
else
{
gi.dprintf( "NULL behavior" );
}
gi.dprintf( "\n" );
#endif
// NULL out our current thread so that EndBehavior doesn't
// signal the thread that the behavior ended.
thread = NULL;
EndBehavior();
assert( !behavior );
// Set the thread after ending the old behavior, but before the new behavior
if ( newstate->thread != -1 )
{
thread = Director.GetThread( newstate->thread );
// Since PopState is called from the thread, we don't need to tell the thread to continue processing.
// In fact, depending upon the state of the thread when we pushed it onto the stack, we may not want
// the thread to continue processing (for example, if the last command was a waitFor). Just restoring the
// position here will tell the thread to continue executing or wait for an event to occur.
// If we ever call PopState from outside of a thread, we MUST check to see if the thread should
// continue execution.
//FIXME
// This is probably an actorthread that was removed
// ADDENDUM: actorThread is now only removed once. Thread should never be NULL.
if ( thread )
{
thread->Restore( &newstate->marker );
}
}
else
{
thread = NULL;
}
// delete the old action/response list
n = actionList.NumObjects();
for( i = n; i >= 1; i-- )
{
delete actionList.ObjectAt( i );
}
actionList.ClearObjectList();
// Copy the new action/response list
n = newstate->actionList.NumObjects();
for( i = 1; i <= n; i++ )
{
actionList.AddObject( newstate->actionList.ObjectAt( i ) );
}
assert( !behavior );
SetBehavior( newstate->behavior, NULL, thread );
delete newstate;
}
else
{
#ifdef DEBUG_PRINT
gi.dprintf( "\n" );
#endif
EndBehavior();
return false;
}
return true;
}
void Actor::PushState
(
const char *newstate,
ScriptThread *newthread,
ThreadMarker *marker
)
{
ActorState *oldstate;
int i;
int n;
oldstate = new ActorState;
// push the old state
#ifdef DEBUG_PRINT
gi.dprintf( "%d : Pushing old state %s\n", numonstack, state.c_str() );
if ( behavior )
{
gi.dprintf( "old behavior %s\n", behavior->getClassname() );
}
else
{
gi.dprintf( "old behavior NULL\n" );
}
gi.dprintf( "new state %s\n", newstate );
#endif
oldstate->name = state;
oldstate->anim = animname;
oldstate->animDoneEvent = animDoneEvent;
animDoneEvent = NULL;
oldstate->path = path;
oldstate->behavior = behavior;
// newthread must always be the old thread
assert( newthread );
oldstate->thread = newthread->ThreadNum();
assert( marker );
oldstate->marker = *marker;
// Copy the action/response list
n = actionList.NumObjects();
for( i = 1; i <= n; i++ )
{
StateInfo *ptr;
StateInfo *newobj;
ptr = actionList.ObjectAt( i );
newobj = new StateInfo;
newobj->action = ptr->action;
newobj->response = ptr->response;
newobj->ignore = ptr->ignore;
oldstate->actionList.AddObject( newobj );
}
numonstack++;
stateStack.Push( oldstate );
// Any SetBehavior following this will delete this behavior, so null it out so that it doesn't happen
if ( behavior )
{
behavior->End( *this );
behavior = NULL;
}
state = newstate;
thread = newthread;
}
//***********************************************************************************************
//
// State control script commands
//
//***********************************************************************************************
void Actor::DefineStateEvent
(
Event *ev
)
{
const char *action;
str response;
ScriptThread *thread;
str script;
int len;
action = ev->GetString( 1 );
response = ev->GetString( 2 );
// check if we have a filename in the label
if ( !strstr( response.c_str(), "::" ) )
{
thread = ev->GetThread();
if ( thread )
{
// add filename to the label so that if we jump to another script, our labels are still valid
response = str( thread->Filename() ) + "::" + response;
}
}
else
{
// prepend our debug directory name
script = ai_actorscript->string;
len = script.length();
// if we have a directory, make sure that it ends with a '/' or a '\'
if ( ( len > 0 ) && ( script[ len - 1 ] != '/' ) && ( script[ len - 1 ] != '\\' ) )
{
script
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -