📄 scriptmaster.cpp
字号:
assert( ent );
sendevent = new Event( *ev );
if ( !updateList.ObjectInList( ent->entnum ) )
{
updateList.AddObject( ent->entnum );
// Tell the object that we're about to send it some orders
ent->ProcessEvent( EV_Script_NewOrders );
}
// Send the command
ent->ProcessEvent( sendevent );
}
}
//
// free up the event
//
delete ev;
}
qboolean ScriptThread::FindEvent
(
const char *name
)
{
if ( !Event::Exists( name ) )
{
ScriptError( "Unknown command '%s'\n", name );
script.SkipToEOL();
return false;
}
return true;
}
EXPORT_FROM_DLL void ScriptThread::ProcessCommand
(
int argc,
const char **argv
)
{
ScriptVariableList *vars;
ScriptVariable *var;
str command;
str name;
Event *event;
Entity *ent;
if ( argc < 1 )
{
return;
}
name = argv[ 0 ];
if ( argc > 1 )
{
command = argv[ 1 ];
}
// Check for variable commands
vars = Director.GetVarGroup( name.c_str() );
if ( vars )
{
var = Director.GetVariable( name.c_str() );
if ( var->isVariableCommand( command.c_str() ) )
{
event = new Event( command );
event->SetSource( EV_FROM_SCRIPT );
event->SetThread( this );
event->SetLineNumber( linenumber );
event->AddTokens( argc - 2, &argv[ 2 ] );
var->ProcessEvent( event );
return;
}
name = var->stringValue();
if ( !name.length() )
{
ScriptError( "Uninitialized variable '%s' used for command '%s'", var->getName(), command.c_str() );
return;
}
else if ( name[ 0 ] != '$' && name[ 0 ] != '@' && name[ 0 ] != '%' && name[ 0 ] != '*' )
{
ScriptError( "Invalid variable command '%s'", command.c_str() );
return;
}
}
// Check for object commands
if ( name[ 0 ] == '$' )
{
if ( FindEvent( command.c_str() ) )
{
event = new Event( command );
event->SetSource( EV_FROM_SCRIPT );
event->SetThread( this );
event->SetLineNumber( linenumber );
event->AddTokens( argc - 2, &argv[ 2 ] );
SendCommandToSlaves( name.c_str(), event );
}
return;
}
// Check for surface commands
if ( name[ 0 ] == '@' )
{
if ( FindEvent( command.c_str() ) )
{
event = new Event( command );
event->SetSource( EV_FROM_SCRIPT );
event->SetThread( this );
event->SetLineNumber( linenumber );
event->AddToken( &name[ 1 ] );
event->AddTokens( argc - 2, &argv[ 2 ] );
surfaceManager.ProcessEvent( event );
}
return;
}
// Check for console commands
if ( name[ 0 ] == '%' )
{
if ( FindEvent( command.c_str() ) )
{
event = new Event( command );
event->SetSource( EV_FROM_SCRIPT );
event->SetThread( this );
event->SetLineNumber( linenumber );
event->AddToken( &name[ 1 ] );
event->AddTokens( argc - 2, &argv[ 2 ] );
consoleManager.ProcessEvent( event );
}
return;
}
// Check for entnum commands
if ( name[ 0 ] == '*' )
{
if ( !IsNumeric( &name[ 1 ] ) )
{
ScriptError( "Expecting numeric value for * command, but found '%s'\n", &name[ 1 ] );
}
else if ( FindEvent( command.c_str() ) )
{
ent = G_GetEntity( atoi( &name[ 1 ] ) );
if ( ent )
{
event = new Event( command );
event->SetSource( EV_FROM_SCRIPT );
event->SetThread( this );
event->SetLineNumber( linenumber );
event->AddTokens( argc - 2, &argv[ 2 ] );
ent->ProcessEvent( event );
}
else
{
ScriptError( "Entity not found for * command\n" );
}
}
return;
}
// Handle global commands
if ( FindEvent( name.c_str() ) )
{
event = new Event( name );
event->SetSource( EV_FROM_SCRIPT );
event->SetThread( this );
event->SetLineNumber( linenumber );
event->AddTokens( argc - 1, &argv[ 1 ] );
if ( !ProcessEvent( event ) )
{
ScriptError( "Invalid global command '%s'\n", name.c_str() );
}
}
}
EXPORT_FROM_DLL void ScriptThread::ProcessCommandFromEvent
(
Event *ev,
int startarg
)
{
int argc;
int numargs;
const char *argv[ MAX_COMMANDS ];
str args[ MAX_COMMANDS ];
int i;
numargs = ev->NumArgs();
if ( numargs < startarg )
{
ev->Error( "Expecting statement after conditional", MAX_COMMANDS );
return;
}
argc = numargs - startarg + 1;
if ( argc >= MAX_COMMANDS )
{
ev->Error( "Line exceeds %d command limit", MAX_COMMANDS );
return;
}
for( i = 0; i < argc; i++ )
{
args[ i ] = ev->GetToken( startarg + i );
argv[ i ] = args[ i ].c_str();
}
ProcessCommand( argc, argv );
}
EXPORT_FROM_DLL void ScriptThread::Start
(
float delay
)
{
CancelEventsOfType( EV_ScriptThread_Execute );
if ( delay < 0 )
ProcessEvent( EV_ScriptThread_Execute );
else
PostEvent( EV_ScriptThread_Execute, delay );
}
EXPORT_FROM_DLL void ScriptThread::Execute
(
Event *ev
)
{
int num;
ScriptThread *oldthread;
int argc;
const char *argv[ MAX_COMMANDS ];
char args[ MAX_COMMANDS ][ MAXTOKEN ];
ScriptVariable *var;
if ( threadDying )
{
return;
}
// set the current game time
if ( !GameTime )
{
GameTime = gameVars.CreateVariable( "time", 0 );
}
GameTime->setFloatValue( level.time );
// clear the updateList so that all objects moved this frame are notified before they receive any commands
// we have to do this here as well as in DoMove, since DoMove may not be called
updateList.ClearObjectList();
oldthread = Director.CurrentThread();
Director.SetCurrentThread( this );
// if we're not being called from another thread, clear the parm variables
if ( !oldthread )
{
parmVars.ClearList();
}
ClearWaitFor();
var = Director.GetVariable( "parm.previousthread" );
if ( oldthread )
{
var->setIntValue( oldthread->ThreadNum() );
}
else
{
var->setIntValue( 0 );
}
var = Director.GetVariable( "parm.currentthread" );
doneProcessing = false;
num = 0;
while( ( num++ < 10000 ) && !doneProcessing && !threadDying )
{
// keep our thread number up to date
var->setIntValue( threadNum );
script.SkipNonToken( true );
// save the line number for errors
linenumber = script.GetLineNumber();
argc = 0;
while( script.TokenAvailable( false ) )
{
if ( argc >= MAX_COMMANDS )
{
ScriptError( "Line exceeds %d command limit", MAX_COMMANDS );
script.SkipToEOL();
break;
}
strcpy( args[ argc ], script.GetToken( false ) );
argv[ argc ] = args[ argc ];
argc++;
}
assert( argc > 0 );
// Ignore labels
if ( args[ 0 ][ strlen( args[ 0 ] ) - 1 ] != ':' )
{
ProcessCommand( argc, argv );
}
}
if ( !doneProcessing )
{
gi.error( "Command overflow. Possible infinite loop in thread '%s'.\n"
"Stopping on line %d of %s\n", threadName.c_str(), script.GetLineNumber(), script.Filename() );
}
Director.SetCurrentThread( oldthread );
// Set the thread number on exit, in case we were called by someone who wants to know our thread
var = Director.GetVariable( "parm.previousthread" );
var->setIntValue( threadNum );
}
EXPORT_FROM_DLL void ScriptThread::ScriptError
(
const char *fmt,
...
)
{
va_list argptr;
char text[ 1024 ];
va_start( argptr, fmt );
vsprintf( text, fmt, argptr );
va_end( argptr );
gi.dprintf( "%s(%d):: %s\n", Filename(), linenumber, text );
}
//****************************************************************************************
//
// global commands
//
//****************************************************************************************
EXPORT_FROM_DLL qboolean ScriptThread::WaitingFor
(
Entity *obj
)
{
assert( obj );
if ( waitingFor.length() )
{
if ( ( ( waitingFor[ 0 ] == '*' ) && ( atoi( &waitingFor.c_str()[ 1 ] ) == obj->entnum ) ) ||
( waitingFor == obj->TargetName() ) )
{
return true;
}
}
return false;
}
EXPORT_FROM_DLL void ScriptThread::ObjectMoveDone
(
Event *ev
)
{
Entity *obj;
obj = ev->GetEntity( 1 );
assert( obj );
#if 0
gi.dprintf( "Move done %d:'%s'\n", obj->entnum, obj->TargetName() );
#endif
if ( WaitingFor( obj ) )
{
waitingNumObjects--;
if ( waitingNumObjects <= 0 )
{
ClearWaitFor();
// start right away
Start( -1 );
}
}
}
void ScriptThread::CreateThread
(
Event *ev
)
{
ScriptThread * pThread;
pThread = Director.CreateThread( &script, ev->GetToken( 1 ) );
if ( pThread )
{
// start right away
pThread->Start( -1 );
}
}
void ScriptThread::TerminateThread
(
Event *ev
)
{
int threadnum;
ScriptThread *thread;
threadnum = 0;
// we specified the thread to kill
if ( ev->NumArgs() > 0 )
{
threadnum = ev->GetInteger( 1 );
}
else
{
thread = ev->GetThread();
if ( thread )
{
threadnum = thread->ThreadNum();
}
}
if ( threadnum != 0 )
{
thread = Director.GetThread( threadnum );
if ( thread && ( thread->GetType() == MODEL_SCRIPT ) && ( ev->GetSource() == EV_FROM_SCRIPT ) )
{
ev->Error( "Can't terminate an actor's thread via script." );
return;
}
Director.KillThread( threadnum );
}
}
void ScriptThread::ControlObject
(
Event *ev
)
{
ev->GetEntity( 1 );
}
void ScriptThread::EventGoto
(
Event *ev
)
{
const char *label;
label = ev->GetToken( 1 );
if ( !Goto( label ) )
{
ev->Error( "Label '%s' not found", label );
}
}
void ScriptThread::EventPause
(
Event *ev
)
{
ClearWaitFor();
doneProcessing = true;
}
void ScriptThread::EventWait
(
Event *ev
)
{
DoMove();
ClearWaitFor();
waitUntil = ev->GetFloat( 1 ) + level.time;
Start( ev->GetFloat( 1 ) );
doneProcessing = true;
}
void ScriptThread::EventWaitFor
(
Event *ev
)
{
Entity *ent;
const char *objname;
const char *tname;
ClearWaitFor();
doneProcessing = true;
ent = ev->GetEntity( 1 );
if ( ent )
{
objname = ev->GetString( 1 );
tname = ent->TargetName();
if ( objname && objname[ 0 ] == '*' )
{
if ( !IsNumeric( &objname[ 1 ] ) )
{
ScriptError( "Expecting *-prefixed numeric value for waitFor command, but found '%s'\n", objname );
return;
}
waitingFor = objname;
}
else if ( !tname || !tname[ 0 ] )
{
// Probably won't happen, but check for it anyway.
ScriptError( "Entity doesn't have a targetname.\n" );
return;
}
else
{
TargetList *tlist;
waitingFor = tname;
//
// set the number of objects that belong to this targetname
//
tlist = GetTargetList( waitingFor );
waitingNumObjects = tlist->list.NumObjects();
if ( waitingNumObjects <= 0 )
{
waitingNumObjects = 1;
ScriptError( "no objects of targetname %s found.\n", tname );
}
else
{
Entity * tent;
int i;
//
// make sure all these objects are in the update list
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -