mirror of
https://github.com/UberGames/EF2GameSource.git
synced 2024-11-10 06:31:42 +00:00
3521 lines
61 KiB
C++
3521 lines
61 KiB
C++
//-----------------------------------------------------------------------------
|
|
//
|
|
// $Logfile:: /Code/DLLs/game/scriptmaster.cpp $
|
|
// $Revision:: 13 $
|
|
// $Author:: Steven $
|
|
// $Date:: 10/04/02 1:32p $
|
|
//
|
|
// Copyright (C) 1997 by Ritual Entertainment, Inc.
|
|
// All rights reserved.
|
|
//
|
|
// This source is may not be distributed and/or modified without
|
|
// expressly written permission by Ritual Entertainment, Inc.
|
|
//
|
|
//
|
|
// DESCRIPTION:
|
|
// Script masters are invisible entities that are spawned at the begining of each
|
|
// map. They simple parse the script and send commands to the specified objects
|
|
// at the apropriate time. Using a combination of simple commands, very complex
|
|
// scripted events can occur.
|
|
//
|
|
|
|
#include "_pch_cpp.h"
|
|
#include "class.h"
|
|
#include "scriptmaster.h"
|
|
#include "container.h"
|
|
#include "scriptvariable.h"
|
|
#include "misc.h"
|
|
#include "specialfx.h"
|
|
#include "worldspawn.h"
|
|
#include "program.h"
|
|
#include "interpreter.h"
|
|
#include "globalcmd.h"
|
|
|
|
|
|
Program program;
|
|
|
|
ScriptVariableList gameVars;
|
|
ScriptVariableList levelVars;
|
|
|
|
//static ScriptVariablePtr GameTime = NULL;
|
|
|
|
/* Event EV_ProcessCommands
|
|
(
|
|
"processCommands",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Not used."
|
|
);
|
|
Event EV_Script_NewOrders
|
|
(
|
|
"newOrders",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Inform script that it is about to get new orders."
|
|
);
|
|
Event EV_ScriptThread_Execute
|
|
(
|
|
"execute",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Execute the thread."
|
|
);
|
|
Event EV_ScriptThread_Callback
|
|
(
|
|
"script_callback",
|
|
EV_DEFAULT,
|
|
"ese",
|
|
"slave name other",
|
|
"Script callback."
|
|
);
|
|
Event EV_ScriptThread_ThreadCallback
|
|
(
|
|
"thread_callback",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Thread callback."
|
|
);
|
|
Event EV_ScriptThread_VariableCallback
|
|
(
|
|
"variable_callback",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Variable callback."
|
|
);
|
|
Event EV_ScriptThread_DeathCallback
|
|
(
|
|
"death_callback",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Death callback."
|
|
);
|
|
Event EV_ScriptThread_CreateThread
|
|
(
|
|
"thread",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"label",
|
|
"Creates a thread starting at label."
|
|
);
|
|
Event EV_ScriptThread_TerminateThread
|
|
(
|
|
"terminate",
|
|
EV_DEFAULT,
|
|
"i",
|
|
"thread_number",
|
|
"Terminates the specified thread or the current one if none specified."
|
|
);
|
|
Event EV_ScriptThread_ControlObject
|
|
(
|
|
"control",
|
|
EV_DEFAULT,
|
|
"e",
|
|
"object",
|
|
"Not used."
|
|
);
|
|
Event EV_ScriptThread_Goto
|
|
(
|
|
"goto",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"label",
|
|
"Goes to the specified label."
|
|
);
|
|
Event EV_ScriptThread_Pause
|
|
(
|
|
"pause",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Pauses the thread."
|
|
);
|
|
Event EV_ScriptThread_Wait
|
|
(
|
|
"wait",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"wait_time",
|
|
"Wait for the specified amount of time."
|
|
);
|
|
Event EV_ScriptThread_WaitFor
|
|
(
|
|
"waitFor",
|
|
EV_DEFAULT,
|
|
"e",
|
|
"ent",
|
|
"Wait for the specified entity."
|
|
);
|
|
Event EV_ScriptThread_WaitForThread
|
|
(
|
|
"waitForThread",
|
|
EV_DEFAULT,
|
|
"i",
|
|
"thread_number",
|
|
"Wait for the specified thread."
|
|
);
|
|
Event EV_ScriptThread_WaitForVariable
|
|
(
|
|
"waitForVariable",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"variable_name",
|
|
"Wait for the specified variable."
|
|
);
|
|
Event EV_ScriptThread_WaitForDeath
|
|
(
|
|
"waitForDeath",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"name",
|
|
"Wait for death."
|
|
);
|
|
Event EV_ScriptThread_WaitForSound
|
|
(
|
|
"waitForSound",
|
|
EV_DEFAULT,
|
|
"sf",
|
|
"sound_name delay",
|
|
"Wait for end of the named sound plus an optional delay."
|
|
);
|
|
Event EV_ScriptThread_WaitForDialog
|
|
(
|
|
"waitForDialog",
|
|
EV_DEFAULT,
|
|
"eF",
|
|
"actor additional_delay",
|
|
"Wait for end of the dialog for the specified actor.\n"
|
|
"If additional_delay is specified, than the actor will\n"
|
|
"wait the dialog length plus the delay."
|
|
);
|
|
Event EV_ScriptThread_WaitForPlayer
|
|
(
|
|
"waitForPlayer",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Wait for player to be ready."
|
|
);
|
|
Event EV_ScriptThread_End
|
|
(
|
|
"end",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"End the thread."
|
|
);
|
|
Event EV_ScriptThread_Print
|
|
(
|
|
"print",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"string",
|
|
"Prints a string."
|
|
);
|
|
Event EV_ScriptThread_PrintInt
|
|
(
|
|
"printint",
|
|
EV_DEFAULT,
|
|
"i",
|
|
"integer",
|
|
"Print integer."
|
|
);
|
|
Event EV_ScriptThread_PrintFloat
|
|
(
|
|
"printfloat",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"float",
|
|
"Prints a float.");
|
|
Event EV_ScriptThread_PrintVector
|
|
(
|
|
"printvector",
|
|
EV_DEFAULT,
|
|
"v",
|
|
"vector",
|
|
"Prints a vector."
|
|
);
|
|
Event EV_ScriptThread_NewLine
|
|
(
|
|
"newline",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Prints a newline."
|
|
);
|
|
Event EV_ScriptThread_Assert
|
|
(
|
|
"assert",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"value",
|
|
"Assert if value is 0."
|
|
);
|
|
Event EV_ScriptThread_Break
|
|
(
|
|
"break",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Asserts so that we can break back into the debugger from script."
|
|
);
|
|
Event EV_ScriptThread_Clear
|
|
(
|
|
"clear",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"var_group",
|
|
"Clears the specified var group."
|
|
);
|
|
Event EV_ScriptThread_Trigger
|
|
(
|
|
"trigger",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"name",
|
|
"Trigger the specified target or entity."
|
|
);
|
|
Event EV_ScriptThread_Spawn
|
|
(
|
|
"spawn",
|
|
EV_CHEAT,
|
|
"sSSSSSSSS",
|
|
"entityname keyname1 value1 keyname2 value2 keyname3 value3 keyname4 value4",
|
|
"Spawn the specified entity."
|
|
);
|
|
Event EV_ScriptThread_Map
|
|
(
|
|
"map",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"map_name",
|
|
"Starts the specified map."
|
|
);
|
|
Event EV_ScriptThread_SetCvar
|
|
(
|
|
"setcvar",
|
|
EV_DEFAULT,
|
|
"ss",
|
|
"cvar_name value",
|
|
"Sets the value of the specified cvar."
|
|
);
|
|
Event EV_ScriptThread_CueCamera
|
|
(
|
|
"cuecamera",
|
|
EV_DEFAULT,
|
|
"eF",
|
|
"entity switchTime",
|
|
"Cue the camera. If switchTime is specified, then the camera\n"
|
|
"will switch over that length of time."
|
|
);
|
|
Event EV_ScriptThread_CuePlayer
|
|
(
|
|
"cueplayer",
|
|
EV_DEFAULT,
|
|
"F",
|
|
"switchTime",
|
|
"Go back to the normal camera. If switchTime is specified,\n"
|
|
"then the camera will switch over that length of time."
|
|
);
|
|
Event EV_ScriptThread_FreezePlayer
|
|
(
|
|
"freezeplayer",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Freeze the player."
|
|
);
|
|
Event EV_ScriptThread_ReleasePlayer
|
|
(
|
|
"releaseplayer",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Release the player."
|
|
);
|
|
Event EV_ScriptThread_FakePlayer
|
|
(
|
|
"fakeplayer",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Will create a fake version of the player, hide the real one and\n"
|
|
"call the fake one 'fakeplayer'."
|
|
);
|
|
Event EV_ScriptThread_RemoveFakePlayer
|
|
(
|
|
"removefakeplayer",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Will delete the fake version of the player, un-hide the real one and\n"
|
|
"return to the normal game"
|
|
);
|
|
|
|
Event EV_ScriptThread_KillEnt
|
|
(
|
|
"killent",
|
|
EV_CHEAT,
|
|
"i",
|
|
"ent_num",
|
|
"Kill the specified entity."
|
|
);
|
|
Event EV_ScriptThread_KillClass
|
|
(
|
|
"killclass",
|
|
EV_CHEAT,
|
|
"sI",
|
|
"class_name except",
|
|
"Kills everything in the specified class except for the specified entity (optional)."
|
|
);
|
|
Event EV_ScriptThread_RemoveEnt
|
|
(
|
|
"removeent",
|
|
EV_CHEAT,
|
|
"i",
|
|
"ent_num",
|
|
"Removes the specified entity."
|
|
);
|
|
Event EV_ScriptThread_RemoveClass
|
|
(
|
|
"removeclass",
|
|
EV_CHEAT,
|
|
"sI",
|
|
"class_name except",
|
|
"Removes everything in the specified class except for the specified entity (optional)."
|
|
);
|
|
|
|
// client/server flow control
|
|
|
|
Event EV_ScriptThread_ServerOnly
|
|
(
|
|
"server",
|
|
EV_DEFAULT,
|
|
"SSSSSS",
|
|
"arg1 arg2 arg3 arg4 arg5 arg6",
|
|
"Server only command."
|
|
);
|
|
Event EV_ScriptThread_ClientOnly
|
|
(
|
|
"client",
|
|
EV_DEFAULT,
|
|
"SSSSSS",
|
|
"arg1 arg2 arg3 arg4 arg5 arg6",
|
|
"Client only command."
|
|
);
|
|
Event EV_ScriptThread_StuffCommand
|
|
(
|
|
"stuffcmd",
|
|
EV_DEFAULT,
|
|
"SSSSSS",
|
|
"arg1 arg2 arg3 arg4 arg5 arg6",
|
|
"Server only command."
|
|
);
|
|
|
|
//
|
|
// world stuff
|
|
//
|
|
Event EV_ScriptThread_RegisterAlias
|
|
(
|
|
"alias",
|
|
EV_DEFAULT,
|
|
"ssSSSS",
|
|
"alias_name real_name arg1 arg2 arg3 arg4",
|
|
"Sets up an alias."
|
|
);
|
|
Event EV_ScriptThread_RegisterAliasAndCache
|
|
(
|
|
"aliascache",
|
|
EV_DEFAULT,
|
|
"ssSSSS",
|
|
"alias_name real_name arg1 arg2 arg3 arg4",
|
|
"Sets up an alias and caches the resourse."
|
|
);
|
|
Event EV_ScriptThread_SetCinematic
|
|
(
|
|
"cinematic",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Turns on cinematic."
|
|
);
|
|
Event EV_ScriptThread_SetNonCinematic
|
|
(
|
|
"noncinematic",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Turns off cinematic."
|
|
);
|
|
Event EV_ScriptThread_SetAllAIOff
|
|
(
|
|
"all_ai_off",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Turns all AI off."
|
|
);
|
|
Event EV_ScriptThread_SetAllAIOn
|
|
(
|
|
"all_ai_on",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Turns all AI back on."
|
|
);
|
|
Event EV_ScriptThread_SetSkipThread
|
|
(
|
|
"skipthread",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"thread_name",
|
|
"Set the thread to skip."
|
|
);
|
|
|
|
// Precache specific
|
|
Event EV_ScriptThread_Precache_Cache
|
|
(
|
|
"cache",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"resource_name",
|
|
"Cache the specified resource."
|
|
);
|
|
// fades for movies
|
|
Event EV_ScriptThread_FadeIn
|
|
(
|
|
"fadein",
|
|
EV_DEFAULT,
|
|
"fffffI",
|
|
"time red green blue alpha mode",
|
|
"Sets up fadein in values."
|
|
);
|
|
Event EV_ScriptThread_FadeOut
|
|
(
|
|
"fadeout",
|
|
EV_DEFAULT,
|
|
"fffffI",
|
|
"time red green blue alpha mode",
|
|
"Sets up fadeout values."
|
|
);
|
|
Event EV_ScriptThread_FadeSound
|
|
(
|
|
"fadesound",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"time",
|
|
"fades the sound out over the given time."
|
|
);
|
|
Event EV_ScriptThread_CameraCommand
|
|
(
|
|
"cam",
|
|
EV_DEFAULT,
|
|
"sSSSSSS",
|
|
"command arg1 arg2 arg3 arg4 arg5 arg6",
|
|
"Processes a camera command."
|
|
);
|
|
|
|
// music command
|
|
Event EV_ScriptThread_MusicEvent
|
|
(
|
|
"music",
|
|
EV_DEFAULT,
|
|
"sS",
|
|
"current fallback",
|
|
"Sets the current and fallback (optional) music moods."
|
|
);
|
|
Event EV_ScriptThread_ForceMusicEvent
|
|
(
|
|
"forcemusic",
|
|
EV_DEFAULT,
|
|
"sS",
|
|
"current fallback",
|
|
"Forces the current and fallback (optional) music moods."
|
|
);
|
|
Event EV_ScriptThread_MusicVolumeEvent
|
|
(
|
|
"musicvolume",
|
|
EV_DEFAULT,
|
|
"ff",
|
|
"volume fade_time",
|
|
"Sets the volume and fade time of the music."
|
|
);
|
|
Event EV_ScriptThread_RestoreMusicVolumeEvent
|
|
(
|
|
"restoremusicvolume",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"fade_time",
|
|
"Restores the music volume to its previous value."
|
|
);
|
|
Event EV_ScriptThread_SoundtrackEvent
|
|
(
|
|
"soundtrack",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"soundtrack_name",
|
|
"Changes the soundtrack."
|
|
);
|
|
Event EV_ScriptThread_RestoreSoundtrackEvent
|
|
(
|
|
"restoresoundtrack",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Restores the soundtrack to the previous one."
|
|
);
|
|
Event EV_ScriptThread_ClearFade
|
|
(
|
|
"clearfade",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Clear the fade from the screen"
|
|
);
|
|
Event EV_ScriptThread_Letterbox
|
|
(
|
|
"letterbox",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"time",
|
|
"Puts the game in letterbox mode."
|
|
);
|
|
Event EV_ScriptThread_ClearLetterbox
|
|
(
|
|
"clearletterbox",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"time",
|
|
"Clears letterbox mode."
|
|
);
|
|
Event EV_ScriptThread_SetDialogScript
|
|
(
|
|
"setdialogscript" ,
|
|
EV_DEFAULT,
|
|
"s",
|
|
"dialog_script",
|
|
"Set the script to be used when dialog:: is used"
|
|
);
|
|
|
|
Event EV_ScriptThread_SetLightStyle
|
|
(
|
|
"setlightstyle" ,
|
|
EV_DEFAULT,
|
|
"is",
|
|
"lightstyleindex lightstyledata",
|
|
"Set up the lightstyle with lightstyleindex to the specified data"
|
|
);
|
|
|
|
Event EV_ScriptThread_KillThreadEvent
|
|
(
|
|
"killthread",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"threadName",
|
|
"kills all threads starting with the specified name"
|
|
);
|
|
|
|
Event EV_ScriptThread_SetThreadNameEvent
|
|
(
|
|
"threadname",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"threadName",
|
|
"sets the name of the thread"
|
|
);
|
|
|
|
Event EV_ScriptThread_CenterPrint
|
|
(
|
|
"centerprint",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"stuffToPrint",
|
|
"prints the included message in the middle of all player's screens"
|
|
);
|
|
|
|
Event EV_ScriptThread_LocationPrint
|
|
(
|
|
"locprint",
|
|
EV_DEFAULT,
|
|
"iis",
|
|
"xoffset yoffset stuffToPrint",
|
|
"prints the included message in the specified location of all player's screens"
|
|
);
|
|
|
|
Event EV_ScriptThread_MissionFailed
|
|
(
|
|
"missionfailed",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Makes the player fail their mission, level restarts."
|
|
);
|
|
Event EV_ScriptThread_ArenaCommand
|
|
(
|
|
"arena",
|
|
EV_DEFAULT,
|
|
"dsSSSSSS",
|
|
"arenanum command arg1 arg2 arg3 arg4 arg5 arg6",
|
|
"Send a command to the specified arena"
|
|
);
|
|
|
|
|
|
CLASS_DECLARATION( Class, ThreadMarker, NULL )
|
|
{
|
|
{ NULL, NULL }
|
|
}; */
|
|
|
|
ScriptMaster Director;
|
|
|
|
CLASS_DECLARATION( Listener, ScriptMaster, NULL )
|
|
{
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
ScriptMaster::ScriptMaster()
|
|
{
|
|
threadIndex = 0;
|
|
currentThread = NULL;
|
|
player_ready = false;
|
|
}
|
|
|
|
ScriptMaster::~ScriptMaster()
|
|
{
|
|
/* if ( GameTime )
|
|
{
|
|
gameVars.RemoveVariable( GameTime );
|
|
GameTime = NULL;
|
|
} */
|
|
CloseScript();
|
|
}
|
|
|
|
void ScriptMaster::CloseScript( void )
|
|
{
|
|
KillThreads();
|
|
ScriptLib.CloseScripts();
|
|
/* if ( GameTime )
|
|
{
|
|
gameVars.RemoveVariable( GameTime );
|
|
GameTime = NULL;
|
|
} */
|
|
}
|
|
|
|
void ScriptMaster::KillThreads( void )
|
|
{
|
|
int i;
|
|
int num;
|
|
|
|
num = Threads.NumObjects();
|
|
|
|
// Clear the waitfor's from each thread before deleting
|
|
// so they don't get triggered.
|
|
for( i = num; i > 0; i-- )
|
|
{
|
|
Threads.ObjectAt( i )->ClearWaitFor();
|
|
}
|
|
|
|
for( i = num; i > 0; i-- )
|
|
{
|
|
delete Threads.ObjectAt( i );
|
|
}
|
|
|
|
Threads.FreeObjectList();
|
|
|
|
threadIndex = 0;
|
|
currentThread = NULL;
|
|
}
|
|
|
|
qboolean ScriptMaster::NotifyOtherThreads( int num )
|
|
{
|
|
CThread *thread1;
|
|
CThread *thread2;
|
|
int i;
|
|
int n;
|
|
Event *ev;
|
|
|
|
thread1 = GetThread( num );
|
|
assert( thread1 );
|
|
n = Threads.NumObjects();
|
|
for( i = 1; i <= n; i++ )
|
|
{
|
|
thread2 = Threads.ObjectAt( i );
|
|
assert( thread2 );
|
|
if ( thread2->WaitingOnThread() == thread1 )
|
|
{
|
|
ev = new Event( EV_ScriptThread_ThreadCallback );
|
|
ev->SetThread( thread1 );
|
|
thread2->ProcessEvent( ev );
|
|
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void ScriptMaster::DeathMessage( const char *name )
|
|
{
|
|
CThread *thread;
|
|
Event *ev;
|
|
int i,n;
|
|
|
|
// Look for threads that are waiting for this name
|
|
n = Threads.NumObjects();
|
|
for( i = 1; i <= n; i++ )
|
|
{
|
|
const char *waiting;
|
|
thread = Threads.ObjectAt( i );
|
|
assert( thread );
|
|
if (thread)
|
|
{
|
|
waiting = thread->WaitingOnDeath();
|
|
if (waiting)
|
|
{
|
|
if (!strcmp(waiting, name))
|
|
{
|
|
ev = new Event( EV_ScriptThread_DeathCallback );
|
|
thread->ProcessEvent(ev);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ScriptMaster::PlayerSpawned( void )
|
|
{
|
|
CThread *thread;
|
|
int i,n;
|
|
|
|
player_ready = true;
|
|
// Look for threads that are waiting for the player
|
|
n = Threads.NumObjects();
|
|
for( i = 1; i <= n; i++ )
|
|
{
|
|
thread = Threads.ObjectAt( i );
|
|
assert( thread );
|
|
if (thread)
|
|
{
|
|
if ( thread->WaitingOnPlayer() )
|
|
{
|
|
thread->ClearWaitFor();
|
|
thread->DelayedStart( 0.0f );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ScriptMaster::KillThread( const str &name )
|
|
{
|
|
int i;
|
|
int num;
|
|
int len;
|
|
const char * ptr;
|
|
CThread *thread;
|
|
bool useWildCard;
|
|
|
|
|
|
useWildCard = false;
|
|
len = 0;
|
|
// see if the name uses a wild card
|
|
ptr = strchr( name.c_str(), '*' );
|
|
if ( ptr )
|
|
{
|
|
len = ptr - name.c_str();
|
|
useWildCard = true;
|
|
}
|
|
|
|
// kill only those threads whose name matches name
|
|
num = Threads.NumObjects();
|
|
|
|
// Clear the waitfor's from each thread before deleting
|
|
// so they don't get triggered.
|
|
for( i = num; i > 0; i-- )
|
|
{
|
|
thread = Threads.ObjectAt( i );
|
|
int result;
|
|
|
|
//With the wild card used, we want to delete any matches of the thread
|
|
//name
|
|
if(useWildCard == true)
|
|
{
|
|
result = strnicmp( thread->ThreadName(), name.c_str(), len );
|
|
}
|
|
else
|
|
{
|
|
//if the wild card is not active, then we want the exact thread
|
|
//name
|
|
result = stricmp( thread->ThreadName(), name.c_str());
|
|
}
|
|
|
|
//if the result is 0, then we have found a thread to delete.
|
|
if ( result == 0 )
|
|
{
|
|
thread->ClearWaitFor();
|
|
if ( currentThread == thread )
|
|
{
|
|
SetCurrentThread( NULL );
|
|
}
|
|
delete thread;
|
|
}
|
|
}
|
|
}
|
|
|
|
qboolean ScriptMaster::KillThread( int num )
|
|
{
|
|
CThread *thread;
|
|
|
|
// Must be safely reentryable so that the thread destructor can tell us that it's being deleted.
|
|
thread = GetThread( num );
|
|
if ( thread )
|
|
{
|
|
thread->ClearWaitFor();
|
|
if ( currentThread == thread )
|
|
{
|
|
SetCurrentThread( NULL );
|
|
}
|
|
delete thread;
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
qboolean ScriptMaster::RemoveThread( int num )
|
|
{
|
|
CThread *thread;
|
|
int i;
|
|
int n;
|
|
|
|
// Must be safely reentryable so that the thread destructor can tell us that it's being deleted.
|
|
n = Threads.NumObjects();
|
|
for( i = n; i > 0; i-- )
|
|
{
|
|
thread = Threads.ObjectAt( i );
|
|
assert( thread );
|
|
if ( thread )
|
|
{
|
|
if ( thread->ThreadNum() == num )
|
|
{
|
|
Threads.ObjectAt( i )->ClearWaitFor();
|
|
Threads.RemoveObjectAt( i );
|
|
if ( currentThread == thread )
|
|
{
|
|
SetCurrentThread( NULL );
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
CThread *ScriptMaster::CurrentThread( void )
|
|
{
|
|
return currentThread;
|
|
}
|
|
|
|
void ScriptMaster::SetCurrentThread( CThread *thread )
|
|
{
|
|
currentThread = thread;
|
|
}
|
|
|
|
CThread *ScriptMaster::CreateThread( Program *program )
|
|
{
|
|
CThread *thread;
|
|
|
|
thread = new CThread;
|
|
|
|
thread->program = program;
|
|
Threads.AddObject( thread );
|
|
|
|
return thread;
|
|
}
|
|
|
|
CThread *ScriptMaster::CreateThread( const char *label, Program *program )
|
|
{
|
|
CThread *thread;
|
|
int threadnum;
|
|
|
|
thread = new CThread;
|
|
thread->program = program;
|
|
|
|
threadnum = GetUniqueThreadNumber();
|
|
Threads.AddObject( thread );
|
|
|
|
if ( !thread->Setup( threadnum, label ) )
|
|
{
|
|
KillThread( threadnum );
|
|
return NULL;
|
|
}
|
|
|
|
return thread;
|
|
}
|
|
|
|
CThread *ScriptMaster::CreateThread( void )
|
|
{
|
|
CThread *thread;
|
|
|
|
thread = new CThread;
|
|
|
|
thread->SetThreadNum( GetUniqueThreadNumber() );
|
|
Threads.AddObject( thread );
|
|
|
|
return thread;
|
|
}
|
|
|
|
CThread *ScriptMaster::CreateThread( const char *label )
|
|
{
|
|
CThread *thread;
|
|
int threadnum;
|
|
|
|
thread = new CThread;
|
|
|
|
threadnum = GetUniqueThreadNumber();
|
|
Threads.AddObject( thread );
|
|
|
|
if ( !thread->Setup( threadnum, label ) )
|
|
{
|
|
KillThread( threadnum );
|
|
return NULL;
|
|
}
|
|
|
|
return thread;
|
|
}
|
|
|
|
CThread *ScriptMaster::GetThread( int num )
|
|
{
|
|
int i;
|
|
int n;
|
|
CThread *thread;
|
|
|
|
n = Threads.NumObjects();
|
|
for( i = 1; i <= n; i++ )
|
|
{
|
|
thread = Threads.ObjectAt( i );
|
|
assert( thread );
|
|
if ( thread )
|
|
{
|
|
if ( thread->ThreadNum() == num )
|
|
{
|
|
return thread;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int ScriptMaster::GetUniqueThreadNumber( void )
|
|
{
|
|
do
|
|
{
|
|
threadIndex++;
|
|
if ( threadIndex == 0 )
|
|
{
|
|
threadIndex = 1;
|
|
}
|
|
}
|
|
while( GetThread( threadIndex ) );
|
|
|
|
return threadIndex;
|
|
}
|
|
|
|
/* qboolean ScriptMaster::labelExists
|
|
(
|
|
GameScript * scr,
|
|
const char *name
|
|
)
|
|
|
|
{
|
|
return scr->labelExists( name );
|
|
}
|
|
|
|
qboolean ScriptMaster::labelExists
|
|
(
|
|
const char *filename,
|
|
const char *name
|
|
)
|
|
{
|
|
GameScript *scr;
|
|
|
|
scr = ScriptLib.GetScript( filename );
|
|
if ( scr )
|
|
{
|
|
return scr->labelExists( name );
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
qboolean ScriptMaster::Goto
|
|
(
|
|
GameScript * scr,
|
|
const char *name
|
|
)
|
|
|
|
{
|
|
return scr->Goto( name );
|
|
}
|
|
|
|
bool ScriptMaster::isVarGroup
|
|
(
|
|
const char *name
|
|
)
|
|
|
|
{
|
|
const char *v;
|
|
char vargroup[ 20 ];
|
|
int len;
|
|
|
|
assert( name );
|
|
if ( !name )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
v = strchr( name, '.' );
|
|
if ( !v )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
len = v - name;
|
|
if ( len > sizeof( vargroup ) - 1 )
|
|
{
|
|
len = sizeof( vargroup ) - 1;
|
|
}
|
|
memset( vargroup, 0, sizeof( vargroup ) );
|
|
strncpy( vargroup, name, len );
|
|
|
|
if ( !strcmp( vargroup, "game" ) || !strcmp( vargroup, "level" ) ||
|
|
!strcmp( vargroup, "local" ) || !strcmp( vargroup, "parm" ) )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
ScriptVariableList *ScriptMaster::GetVarGroup
|
|
(
|
|
const char *name
|
|
)
|
|
|
|
{
|
|
ScriptVariableList *vars;
|
|
const char *v;
|
|
char vargroup[ 20 ];
|
|
int len;
|
|
|
|
v = strchr( name, '.' );
|
|
if ( !v )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
len = v - name;
|
|
if ( len > sizeof( vargroup ) - 1 )
|
|
{
|
|
len = sizeof( vargroup ) - 1;
|
|
}
|
|
memset( vargroup, 0, sizeof( vargroup ) );
|
|
strncpy( vargroup, name, len );
|
|
|
|
vars = NULL;
|
|
if ( !strcmp( vargroup, "game" ) )
|
|
{
|
|
vars = &gameVars;
|
|
}
|
|
else if ( !strcmp( vargroup, "level" ) )
|
|
{
|
|
vars = &levelVars;
|
|
}
|
|
else if ( !strcmp( vargroup, "local" ) && currentThread )
|
|
{
|
|
vars = currentThread->Vars();
|
|
}
|
|
else if ( !strcmp( vargroup, "parm" ) )
|
|
{
|
|
vars = &parmVars;
|
|
}
|
|
|
|
return vars;
|
|
}
|
|
|
|
ScriptVariable *ScriptMaster::GetExistingVariable
|
|
(
|
|
const char *name
|
|
)
|
|
|
|
{
|
|
ScriptVariableList *vars;
|
|
const char *v;
|
|
|
|
vars = GetVarGroup( name );
|
|
if ( !vars )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
v = strchr( name, '.' );
|
|
if ( !v )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
return vars->GetVariable( v + 1 );
|
|
}
|
|
|
|
ScriptVariable *ScriptMaster::GetVariable
|
|
(
|
|
const char *name
|
|
)
|
|
|
|
{
|
|
ScriptVariable *var;
|
|
ScriptVariableList *vars;
|
|
const char *v;
|
|
|
|
var = GetExistingVariable( name );
|
|
if ( !var )
|
|
{
|
|
vars = GetVarGroup( name );
|
|
if ( !vars )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
v = strchr( name, '.' );
|
|
assert( v );
|
|
var = vars->CreateVariable( v + 1, "" );
|
|
}
|
|
|
|
return var;
|
|
} */
|
|
|
|
/*
|
|
CLASS_DECLARATION( Listener, ScriptThread, NULL )
|
|
{
|
|
{ &EV_ScriptThread_Execute, Execute },
|
|
{ &EV_MoveDone, ObjectMoveDone },
|
|
{ &EV_ScriptThread_Callback, ScriptCallback },
|
|
{ &EV_ScriptThread_ThreadCallback, ThreadCallback },
|
|
{ &EV_ScriptThread_VariableCallback, VariableCallback },
|
|
{ &EV_ScriptThread_DeathCallback, DeathCallback },
|
|
{ &EV_ScriptThread_CreateThread, CreateThread },
|
|
{ &EV_ScriptThread_TerminateThread, TerminateThread },
|
|
{ &EV_ScriptThread_ControlObject, ControlObject },
|
|
{ &EV_ScriptThread_Goto, EventGoto },
|
|
{ &EV_ScriptThread_Pause, EventPause },
|
|
{ &EV_ScriptThread_Wait, EventWait },
|
|
{ &EV_ScriptThread_WaitFor, EventWaitFor },
|
|
{ &EV_ScriptThread_WaitForThread, EventWaitForThread },
|
|
{ &EV_ScriptThread_WaitForVariable, EventWaitForVariable },
|
|
{ &EV_ScriptThread_WaitForDeath, EventWaitForDeath },
|
|
{ &EV_ScriptThread_WaitForSound, EventWaitForSound },
|
|
{ &EV_ScriptThread_WaitForDialog, EventWaitForDialog },
|
|
{ &EV_ScriptThread_WaitForPlayer, EventWaitForPlayer },
|
|
{ &EV_ScriptThread_End, EventEnd },
|
|
{ &EV_ScriptThread_Print, Print },
|
|
{ &EV_ScriptThread_PrintInt, PrintInt },
|
|
{ &EV_ScriptThread_PrintFloat, PrintFloat },
|
|
{ &EV_ScriptThread_PrintVector, PrintVector },
|
|
{ &EV_ScriptThread_NewLine, NewLine },
|
|
{ &EV_ScriptThread_Assert, Assert },
|
|
{ &EV_ScriptThread_Break, Break },
|
|
{ &EV_ScriptThread_Clear, Clear },
|
|
{ &EV_ScriptThread_Trigger, TriggerEvent },
|
|
{ &EV_ScriptThread_ServerOnly, ServerEvent },
|
|
{ &EV_ScriptThread_ClientOnly, ClientEvent },
|
|
{ &EV_ScriptThread_StuffCommand, StuffCommand },
|
|
{ &EV_ScriptThread_Spawn, Spawn },
|
|
{ &EV_ScriptThread_Precache_Cache, CacheResourceEvent },
|
|
{ &EV_ScriptThread_RegisterAlias, RegisterAlias },
|
|
{ &EV_ScriptThread_RegisterAliasAndCache, RegisterAliasAndCache },
|
|
{ &EV_ScriptThread_Map, MapEvent },
|
|
{ &EV_ScriptThread_SetCvar, SetCvarEvent },
|
|
{ &EV_ScriptThread_CueCamera, CueCamera },
|
|
{ &EV_ScriptThread_CuePlayer, CuePlayer },
|
|
{ &EV_ScriptThread_FreezePlayer, FreezePlayer },
|
|
{ &EV_ScriptThread_ReleasePlayer, ReleasePlayer },
|
|
{ &EV_ScriptThread_FadeIn, FadeIn },
|
|
{ &EV_ScriptThread_FadeOut, FadeOut },
|
|
{ &EV_ScriptThread_FadeSound, FadeSound },
|
|
{ &EV_ScriptThread_ClearFade, ClearFade },
|
|
{ &EV_ScriptThread_Letterbox, Letterbox },
|
|
{ &EV_ScriptThread_ClearLetterbox, ClearLetterbox },
|
|
{ &EV_ScriptThread_MusicEvent, MusicEvent },
|
|
{ &EV_ScriptThread_ForceMusicEvent, ForceMusicEvent },
|
|
{ &EV_ScriptThread_MusicVolumeEvent, MusicVolumeEvent },
|
|
{ &EV_ScriptThread_RestoreMusicVolumeEvent, RestoreMusicVolumeEvent },
|
|
{ &EV_ScriptThread_SoundtrackEvent, SoundtrackEvent },
|
|
{ &EV_ScriptThread_RestoreSoundtrackEvent, RestoreSoundtrackEvent },
|
|
{ &EV_ScriptThread_CameraCommand, CameraCommand },
|
|
{ &EV_ScriptThread_SetCinematic, SetCinematic },
|
|
{ &EV_ScriptThread_SetNonCinematic, SetNonCinematic },
|
|
{ &EV_ScriptThread_SetAllAIOff, SetAllAIOff },
|
|
{ &EV_ScriptThread_SetAllAIOn, SetAllAIOn },
|
|
{ &EV_ScriptThread_SetSkipThread, SetSkipThread },
|
|
{ &EV_ScriptThread_KillEnt, KillEnt },
|
|
{ &EV_ScriptThread_RemoveEnt, RemoveEnt },
|
|
{ &EV_ScriptThread_KillClass, KillClass },
|
|
{ &EV_ScriptThread_RemoveClass, RemoveClass },
|
|
{ &EV_ScriptThread_FakePlayer, FakePlayer },
|
|
{ &EV_ScriptThread_RemoveFakePlayer, RemoveFakePlayer },
|
|
{ &EV_ScriptThread_SetDialogScript, SetDialogScript },
|
|
{ &EV_ScriptThread_SetLightStyle, SetLightStyle },
|
|
{ &EV_ScriptThread_KillThreadEvent, KillThreadEvent },
|
|
{ &EV_ScriptThread_SetThreadNameEvent, SetThreadName },
|
|
{ &EV_ScriptThread_CenterPrint, CenterPrint },
|
|
{ &EV_ScriptThread_LocationPrint, LocationPrint },
|
|
{ &EV_ScriptThread_MissionFailed, MissionFailed },
|
|
{ &EV_ScriptThread_ArenaCommand, ArenaCommand },
|
|
{ &EV_AI_RecalcPaths, PassToPathmanager },
|
|
{ &EV_AI_CalcPath, PassToPathmanager },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
ScriptThread::ScriptThread()
|
|
{
|
|
threadNum = 0;
|
|
ClearWaitFor();
|
|
threadDying = false;
|
|
doneProcessing = true;
|
|
type = LEVEL_SCRIPT;
|
|
}
|
|
|
|
ScriptThread::~ScriptThread()
|
|
{
|
|
Director.NotifyOtherThreads( threadNum );
|
|
Director.RemoveThread( threadNum );
|
|
}
|
|
|
|
void ScriptThread::ClearWaitFor
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
waitUntil = 0;
|
|
waitingFor = "";
|
|
waitingNumObjects = 0;
|
|
waitingForThread = NULL;
|
|
waitingForVariable = "";
|
|
waitingForDeath = "";
|
|
waitingForPlayer = false;
|
|
}
|
|
|
|
void ScriptThread::SetType
|
|
(
|
|
scripttype_t newtype
|
|
)
|
|
|
|
{
|
|
type = newtype;
|
|
}
|
|
|
|
scripttype_t ScriptThread::GetType
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
return type;
|
|
}
|
|
|
|
void ScriptThread::SetThreadNum
|
|
(
|
|
int num
|
|
)
|
|
|
|
{
|
|
threadNum = num;
|
|
}
|
|
|
|
int ScriptThread::ThreadNum
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
return threadNum;
|
|
}
|
|
|
|
const char *ScriptThread::ThreadName
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
return threadName.c_str();
|
|
}
|
|
|
|
void ScriptThread::SetThreadName
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
threadName = ev->GetString( 1 );
|
|
}
|
|
|
|
int ScriptThread::CurrentLine
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
return linenumber;
|
|
}
|
|
|
|
const char *ScriptThread::Filename
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
return script.Filename();
|
|
}
|
|
|
|
ScriptThread *ScriptThread::WaitingOnThread
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
return waitingForThread;
|
|
}
|
|
|
|
const char *ScriptThread::WaitingOnVariable
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
return waitingForVariable.c_str();
|
|
}
|
|
|
|
const char *ScriptThread::WaitingOnDeath
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
return waitingForDeath.c_str();
|
|
}
|
|
|
|
qboolean ScriptThread::WaitingOnPlayer
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
return waitingForPlayer;
|
|
}
|
|
|
|
ScriptVariableList *ScriptThread::Vars
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
return &localVars;
|
|
}
|
|
|
|
|
|
qboolean ScriptThread::Setup
|
|
(
|
|
int num,
|
|
GameScript *scr,
|
|
const char *label
|
|
)
|
|
|
|
{
|
|
threadNum = num;
|
|
|
|
ClearWaitFor();
|
|
script.SetSourceScript( scr );
|
|
if ( label && !Goto( label ) )
|
|
{
|
|
ScriptError( "Can't create thread. Label '%s' not found", label );
|
|
return false;
|
|
}
|
|
|
|
if ( label )
|
|
{
|
|
threadName = label;
|
|
}
|
|
else
|
|
{
|
|
threadName = script.Filename();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
qboolean ScriptThread::SetScript
|
|
(
|
|
const char *name
|
|
)
|
|
|
|
{
|
|
GameScript *scr;
|
|
|
|
scr = ScriptLib.GetScript( name );
|
|
if ( scr )
|
|
{
|
|
Setup( threadNum, scr, NULL );
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
qboolean ScriptThread::Goto
|
|
(
|
|
const char *name
|
|
)
|
|
|
|
{
|
|
qboolean result;
|
|
|
|
result = ScriptLib.Goto( &script, name );
|
|
if ( result )
|
|
{
|
|
// Cancel pending execute events when waitUntil is set
|
|
if ( waitUntil )
|
|
{
|
|
CancelEventsOfType( EV_ScriptThread_Execute );
|
|
}
|
|
ClearWaitFor();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
qboolean ScriptThread::labelExists
|
|
(
|
|
const char *name
|
|
)
|
|
|
|
{
|
|
return ScriptLib.labelExists( &script, name );
|
|
}
|
|
|
|
void ScriptThread::Mark
|
|
(
|
|
ThreadMarker *mark
|
|
)
|
|
|
|
{
|
|
assert( mark );
|
|
|
|
mark->linenumber = linenumber;
|
|
mark->doneProcessing = doneProcessing;
|
|
mark->waitingFor = waitingFor;
|
|
mark->waitingForThread = waitingForThread;
|
|
mark->waitingForVariable = waitingForVariable;
|
|
mark->waitingForDeath = waitingForDeath;
|
|
mark->waitingForPlayer = waitingForPlayer;
|
|
mark->waitingNumObjects = waitingNumObjects;
|
|
if ( waitUntil )
|
|
{
|
|
// add one so that 0 is always reserved for no wait
|
|
mark->waitUntil = waitUntil - level.time + 1;
|
|
}
|
|
else
|
|
{
|
|
mark->waitUntil = 0;
|
|
}
|
|
|
|
script.Mark( &mark->scriptmarker );
|
|
}
|
|
|
|
void ScriptThread::Restore
|
|
(
|
|
ThreadMarker *mark
|
|
)
|
|
|
|
{
|
|
assert( mark );
|
|
|
|
linenumber = mark->linenumber;
|
|
doneProcessing = mark->doneProcessing;
|
|
|
|
waitingFor = mark->waitingFor;
|
|
waitingForThread = mark->waitingForThread;
|
|
waitingForVariable = mark->waitingForVariable;
|
|
waitingForDeath = mark->waitingForDeath;
|
|
waitingForPlayer = mark->waitingForPlayer;
|
|
waitingNumObjects = mark->waitingNumObjects;
|
|
|
|
script.Restore( &mark->scriptmarker );
|
|
|
|
if ( mark->waitUntil )
|
|
{
|
|
// subtract one since we added one when we stored it.
|
|
// this way, 0 is always reserved for no wait
|
|
// Cheezy, yeah, but since I'm commenting it, it's "ok". :)
|
|
waitUntil = mark->waitUntil + level.time - 1;
|
|
Start( waitUntil - level.time );
|
|
}
|
|
}
|
|
|
|
TargetList *ScriptThread::GetTargetList
|
|
(
|
|
const str &targetname
|
|
)
|
|
{
|
|
TargetList *tlist;
|
|
int num;
|
|
int i;
|
|
|
|
num = targets.NumObjects();
|
|
for( i = 1; i <= num; i++ )
|
|
{
|
|
tlist = targets.ObjectAt( i );
|
|
if ( targetname == tlist->targetname )
|
|
{
|
|
return tlist;
|
|
}
|
|
}
|
|
|
|
tlist = world->GetTargetList( targetname );
|
|
targets.AddObject( tlist );
|
|
|
|
return tlist;
|
|
}
|
|
|
|
void ScriptThread::SendCommandToSlaves
|
|
(
|
|
const char *name,
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
Event *sendevent;
|
|
Entity *ent;
|
|
TargetList *tlist;
|
|
int i;
|
|
int num;
|
|
|
|
if ( name && name[ 0 ] )
|
|
{
|
|
tlist = GetTargetList( str(name+1) );
|
|
num = tlist->list.NumObjects();
|
|
for ( i = 1; i <= num; i++ )
|
|
{
|
|
ent = tlist->list.ObjectAt( i );
|
|
|
|
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 );
|
|
}
|
|
if ( !num )
|
|
{
|
|
warning( "SendCommandToSlaves", "Could not find target %s in world.\n", name );
|
|
}
|
|
}
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
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 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() );
|
|
}
|
|
}
|
|
}
|
|
|
|
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 );
|
|
}
|
|
|
|
void ScriptThread::Start
|
|
(
|
|
float delay
|
|
)
|
|
{
|
|
CancelEventsOfType( EV_ScriptThread_Execute );
|
|
PostEvent( EV_ScriptThread_Execute, delay );
|
|
}
|
|
|
|
void ScriptThread::StartImmediately
|
|
(
|
|
void
|
|
)
|
|
{
|
|
CancelEventsOfType( EV_ScriptThread_Execute );
|
|
ProcessEvent( EV_ScriptThread_Execute );
|
|
}
|
|
|
|
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( ERR_DROP, "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 );
|
|
}
|
|
|
|
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
|
|
//
|
|
//****************************************************************************************
|
|
|
|
/* 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;
|
|
}
|
|
|
|
void ScriptThread::ObjectMoveDone
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
Entity *obj;
|
|
|
|
obj = ev->GetEntity( 1 );
|
|
|
|
if ( !obj )
|
|
{
|
|
gi.DPrintf( "Object no longer exists, MoveDone invalid now\n" );
|
|
return;
|
|
}
|
|
|
|
#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( 0 );
|
|
}
|
|
}
|
|
}
|
|
|
|
void ScriptThread::CreateThread
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
ScriptThread * pThread;
|
|
|
|
pThread = Director.CreateThread( &script, ev->GetToken( 1 ) );
|
|
if ( pThread )
|
|
{
|
|
// start right away
|
|
pThread->StartImmediately();
|
|
}
|
|
}
|
|
|
|
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
|
|
)
|
|
|
|
{
|
|
DoMove();
|
|
|
|
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();
|
|
//
|
|
// we need to make sure we have an entity we are going to wait for
|
|
//
|
|
|
|
ent = ev->GetEntity( 1 );
|
|
if ( ent )
|
|
{
|
|
doneProcessing = true;
|
|
|
|
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
|
|
//
|
|
for ( i = 1; i <= waitingNumObjects; i++ )
|
|
{
|
|
tent = tlist->list.ObjectAt( i );
|
|
// add the object to the update list to make sure we tell it to do a move
|
|
if ( !updateList.ObjectInList( tent->entnum ) )
|
|
{
|
|
updateList.AddObject( tent->entnum );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// add the object to the update list to make sure we tell it to do a move
|
|
if ( !updateList.ObjectInList( ent->entnum ) )
|
|
{
|
|
updateList.AddObject( ent->entnum );
|
|
}
|
|
}
|
|
|
|
DoMove();
|
|
}
|
|
|
|
void ScriptThread::EventWaitForThread
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
ClearWaitFor();
|
|
waitingForThread = Director.GetThread( ev->GetInteger( 1 ) );
|
|
if ( !waitingForThread )
|
|
{
|
|
ev->Error( "EventWaitForThread", "Thread %d not running", ev->GetInteger( 1 ) );
|
|
return;
|
|
}
|
|
doneProcessing = true;
|
|
|
|
DoMove();
|
|
}
|
|
|
|
void ScriptThread::EventWaitForDeath
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
ClearWaitFor();
|
|
waitingForDeath = ev->GetString(1);
|
|
if ( !waitingForDeath.length() )
|
|
{
|
|
ev->Error( "EventWaitForDeath", "Null name" );
|
|
return;
|
|
}
|
|
doneProcessing = true;
|
|
|
|
DoMove();
|
|
}
|
|
|
|
void ScriptThread::EventWaitForVariable
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
ClearWaitFor();
|
|
waitingForVariable = ev->GetString(1);
|
|
|
|
if ( !waitingForVariable.length() )
|
|
{
|
|
ev->Error( "EventWaitForVariable", "Null variable" );
|
|
return;
|
|
}
|
|
doneProcessing = true;
|
|
|
|
DoMove();
|
|
}
|
|
|
|
void ScriptThread::EventWaitForSound
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
str sound;
|
|
float delay;
|
|
|
|
ClearWaitFor();
|
|
|
|
DoMove();
|
|
|
|
delay = 0;
|
|
sound = ev->GetString( 1 );
|
|
|
|
delay = gi.SoundLength( sound.c_str() );
|
|
|
|
if ( delay < 0 )
|
|
gi.DPrintf( "Lip file not found for dialog %s\n", sound.c_str() );
|
|
|
|
if ( ev->NumArgs() > 1 )
|
|
delay += ev->GetFloat( 2 );
|
|
|
|
Start( delay );
|
|
doneProcessing = true;
|
|
}
|
|
|
|
void ScriptThread::EventWaitForDialog
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
float delay;
|
|
Actor *act;
|
|
Entity *ent;
|
|
|
|
ClearWaitFor();
|
|
|
|
ent = ev->GetEntity( 1 );
|
|
|
|
if ( ent && ent->isSubclassOf( Actor ) )
|
|
{
|
|
act = (Actor *)ent;
|
|
|
|
delay = act->GetDialogRemainingTime( );
|
|
if ( ev->NumArgs() > 1 )
|
|
{
|
|
delay += ev->GetFloat( 2 );
|
|
}
|
|
Start( delay );
|
|
doneProcessing = true;
|
|
}
|
|
}
|
|
|
|
void ScriptThread::EventWaitForPlayer
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
doneProcessing = true;
|
|
|
|
ClearWaitFor();
|
|
waitingForPlayer = true;
|
|
|
|
DoMove();
|
|
}
|
|
|
|
void ScriptThread::EventEnd
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
ScriptVariable *var;
|
|
const char *text;
|
|
Entity *ent;
|
|
|
|
ClearWaitFor();
|
|
|
|
// If we're a model script, we have to tell our owning entity that we're done.
|
|
if ( ( ev->GetSource() == EV_FROM_SCRIPT ) && ( type == MODEL_SCRIPT ) )
|
|
{
|
|
doneProcessing = true;
|
|
var = Vars()->GetVariable( "self" );
|
|
if ( !var )
|
|
{
|
|
ev->Error( "Model script ending without local.self set" );
|
|
}
|
|
else
|
|
{
|
|
text = var->stringValue();
|
|
if ( ( text[ 0 ] == '*' ) && IsNumeric( &text[ 1 ] ) )
|
|
{
|
|
ent = G_GetEntity( atoi( &text[ 1 ] ) );
|
|
|
|
// pass the event on to entity pointed to by self
|
|
if ( ent )
|
|
{
|
|
Event * newevent;
|
|
|
|
newevent = new Event( ev );
|
|
ent->ProcessEvent( newevent );
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ev->Error( "Model script ending. Invalid value in local.self '%s'", text );
|
|
}
|
|
}
|
|
}
|
|
|
|
Director.NotifyOtherThreads( threadNum );
|
|
PostEvent( EV_Remove, 0 );
|
|
doneProcessing = true;
|
|
threadDying = true;
|
|
}
|
|
|
|
void ScriptThread::Print
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
gi.DPrintf( "%s", ev->GetString( 1 ) );
|
|
}
|
|
|
|
void ScriptThread::PrintInt
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
gi.DPrintf( "%d", ev->GetInteger( 1 ) );
|
|
}
|
|
|
|
void ScriptThread::PrintFloat
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
gi.DPrintf( "%.2f", ev->GetFloat( 1 ) );
|
|
}
|
|
|
|
void ScriptThread::PrintVector
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
Vector vec;
|
|
|
|
vec = ev->GetVector( 1 );
|
|
gi.DPrintf( "(%.2f %.2f %.2f)", vec.x, vec.y, vec.z );
|
|
}
|
|
|
|
void ScriptThread::NewLine
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
gi.DPrintf( "\n" );
|
|
}
|
|
|
|
void ScriptThread::Assert
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
assert( ev->GetFloat( 1 ) );
|
|
}
|
|
|
|
void ScriptThread::Break
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
// Break into the debugger
|
|
assert( 0 );
|
|
}
|
|
|
|
void ScriptThread::Clear
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
ScriptVariableList *vars;
|
|
|
|
vars = Director.GetVarGroup( ev->GetToken( 1 ) );
|
|
if ( vars )
|
|
{
|
|
vars->ClearList();
|
|
}
|
|
}
|
|
|
|
void ScriptThread::ScriptCallback
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
char name[ MAXTOKEN ];
|
|
Entity *other;
|
|
Entity *slave;
|
|
|
|
if ( threadDying )
|
|
{
|
|
return;
|
|
}
|
|
|
|
slave = ev->GetEntity( 1 );
|
|
strcpy( name, ev->GetString( 2 ) );
|
|
other = ev->GetEntity( 3 );
|
|
|
|
if ( !Goto( name ) )
|
|
{
|
|
ev->Error( "Label '%s' not found", name );
|
|
}
|
|
else
|
|
{
|
|
// kill any execute events (in case our last command was "wait")
|
|
ClearWaitFor();
|
|
// start right away
|
|
StartImmediately();
|
|
}
|
|
}
|
|
|
|
void ScriptThread::ThreadCallback
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
ScriptThread *thread;
|
|
|
|
if ( threadDying )
|
|
{
|
|
return;
|
|
}
|
|
|
|
thread = ev->GetThread();
|
|
|
|
if ( thread && ( thread == waitingForThread ) )
|
|
{
|
|
ClearWaitFor();
|
|
StartImmediately();
|
|
}
|
|
}
|
|
|
|
void ScriptThread::VariableCallback
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
ClearWaitFor();
|
|
// start right away
|
|
Start( 0 );
|
|
}
|
|
|
|
void ScriptThread::DeathCallback
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
if ( threadDying )
|
|
{
|
|
return;
|
|
}
|
|
|
|
ClearWaitFor();
|
|
// start right away
|
|
Start( 0 );
|
|
}
|
|
|
|
void ScriptThread::DoMove
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
int entnum;
|
|
Entity *ent;
|
|
Event *event;
|
|
int count;
|
|
int i;
|
|
|
|
count = updateList.NumObjects();
|
|
|
|
for( i = 1; i <= count; i++ )
|
|
{
|
|
entnum = ( int )updateList.ObjectAt( i );
|
|
ent = G_GetEntity( entnum );
|
|
if ( ent )
|
|
{
|
|
if ( ent->ValidEvent( EV_ProcessCommands ) )
|
|
{
|
|
event = new Event( EV_ProcessCommands );
|
|
event->SetThread( this );
|
|
ent->PostEvent( event, 0 );
|
|
}
|
|
else
|
|
{
|
|
// try to remove this from the update list
|
|
if ( waitingNumObjects > 0 )
|
|
{
|
|
waitingNumObjects--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
updateList.ClearObjectList();
|
|
}
|
|
|
|
void ScriptThread::TriggerEvent
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
const char *name;
|
|
Event *event;
|
|
Entity *ent;
|
|
TargetList *tlist;
|
|
int i;
|
|
int num;
|
|
|
|
name = ev->GetString( 1 );
|
|
|
|
// Check for object commands
|
|
if ( name && name[ 0 ] == '$' )
|
|
{
|
|
tlist = GetTargetList( str( name + 1 ) );
|
|
num = tlist->list.NumObjects();
|
|
for ( i = 1; i <= num; i++ )
|
|
{
|
|
ent = tlist->list.ObjectAt( i );
|
|
|
|
assert( ent );
|
|
|
|
event = new Event( EV_Activate );
|
|
event->SetSource( EV_FROM_SCRIPT );
|
|
event->SetThread( this );
|
|
event->SetLineNumber( linenumber );
|
|
event->AddEntity( world );
|
|
ent->ProcessEvent( event );
|
|
}
|
|
}
|
|
else if ( name[ 0 ] == '*' ) // Check for entnum commands
|
|
{
|
|
if ( !IsNumeric( &name[ 1 ] ) )
|
|
{
|
|
ScriptError( "Expecting numeric value for * command, but found '%s'\n", &name[ 1 ] );
|
|
}
|
|
else
|
|
{
|
|
ent = G_GetEntity( atoi( &name[ 1 ] ) );
|
|
if ( ent )
|
|
{
|
|
event = new Event( EV_Activate );
|
|
event->SetSource( EV_FROM_SCRIPT );
|
|
event->SetThread( this );
|
|
event->SetLineNumber( linenumber );
|
|
event->AddEntity( world );
|
|
ent->ProcessEvent( event );
|
|
}
|
|
else
|
|
{
|
|
ScriptError( "Entity not found for * command\n" );
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
ScriptError( "Invalid entity reference '%s'.\n", name );
|
|
}
|
|
}
|
|
|
|
void ScriptThread::ServerEvent
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
int i, argc;
|
|
const char *argv[ MAX_COMMANDS ];
|
|
|
|
argc = 0;
|
|
for ( i = 1; i <= ev->NumArgs(); i++ )
|
|
{
|
|
argv[argc++] = ev->GetString( i );
|
|
}
|
|
|
|
if (argc)
|
|
{
|
|
ProcessCommand( argc, argv );
|
|
}
|
|
}
|
|
|
|
void ScriptThread::ClientEvent
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
//
|
|
// do nothing
|
|
//
|
|
}
|
|
|
|
void ScriptThread::CacheResourceEvent
|
|
(
|
|
Event * ev
|
|
)
|
|
|
|
{
|
|
if ( !precache->integer )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( world )
|
|
{
|
|
CacheResource( ev->GetString( 1 ), world );
|
|
}
|
|
else
|
|
{
|
|
CacheResource( ev->GetString( 1 ), NULL );
|
|
}
|
|
}
|
|
|
|
void ScriptThread::RegisterAlias
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
char parameters[100];
|
|
int i;
|
|
|
|
// Get the parameters for this alias command
|
|
|
|
parameters[0] = 0;
|
|
|
|
for( i = 3 ; i <= ev->NumArgs() ; i++ )
|
|
{
|
|
strcat( parameters, ev->GetString( i ) );
|
|
strcat( parameters, " ");
|
|
}
|
|
|
|
gi.GlobalAlias_Add( ev->GetString( 1 ), ev->GetString( 2 ), parameters );
|
|
}
|
|
|
|
void ScriptThread::RegisterAliasAndCache
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
RegisterAlias(ev);
|
|
|
|
if ( !precache->integer )
|
|
return;
|
|
|
|
CacheResource( ev->GetString( 2 ) );
|
|
}
|
|
|
|
void ScriptThread::MapEvent
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
if ( level.mission_failed )
|
|
return;
|
|
|
|
G_BeginIntermission( ev->GetString( 1 ) );
|
|
doneProcessing = true;
|
|
}
|
|
|
|
void ScriptThread::SetCvarEvent
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
str name;
|
|
|
|
name = ev->GetString( 1 );
|
|
if ( name != "" )
|
|
{
|
|
gi.cvar_set( name.c_str(), ev->GetString( 2 ) );
|
|
}
|
|
}
|
|
|
|
void ScriptThread::CueCamera
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
float switchTime;
|
|
Entity *ent;
|
|
|
|
if ( ev->NumArgs() > 1 )
|
|
{
|
|
switchTime = ev->GetFloat( 2 );
|
|
}
|
|
else
|
|
{
|
|
switchTime = 0;
|
|
}
|
|
|
|
ent = ev->GetEntity( 1 );
|
|
if ( ent )
|
|
{
|
|
SetCamera( ent, switchTime );
|
|
}
|
|
else
|
|
{
|
|
ev->Error( "Camera named %s not found", ev->GetString( 1 ) );
|
|
}
|
|
}
|
|
|
|
void ScriptThread::CuePlayer
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
float switchTime;
|
|
|
|
if ( ev->NumArgs() > 0 )
|
|
{
|
|
switchTime = ev->GetFloat( 1 );
|
|
}
|
|
else
|
|
{
|
|
switchTime = 0;
|
|
}
|
|
|
|
SetCamera( NULL, switchTime );
|
|
}
|
|
|
|
void ScriptThread::FreezePlayer
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
level.playerfrozen = true;
|
|
}
|
|
|
|
void ScriptThread::ReleasePlayer
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
level.playerfrozen = false;
|
|
}
|
|
|
|
void ScriptThread::FakePlayer
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
qboolean holster;
|
|
Player *player;
|
|
|
|
player = ( Player * )g_entities[ 0 ].entity;
|
|
|
|
if ( ( ev->NumArgs() < 1 ) || ev->GetBoolean( 1 ) )
|
|
{
|
|
holster = true;
|
|
}
|
|
else
|
|
{
|
|
holster = false;
|
|
}
|
|
|
|
if ( player && player->edict->inuse && player->edict->client )
|
|
{
|
|
player->FakePlayer( holster );
|
|
}
|
|
}
|
|
|
|
void ScriptThread::RemoveFakePlayer
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
Player *player;
|
|
|
|
player = ( Player * )g_entities[ 0 ].entity;
|
|
|
|
if ( player && player->edict->inuse && player->edict->client )
|
|
{
|
|
player->RemoveFakePlayer();
|
|
}
|
|
}
|
|
|
|
void ScriptThread::Spawn
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
Entity *ent;
|
|
Entity *tent;
|
|
const char *name;
|
|
ClassDef *cls;
|
|
int n;
|
|
int i;
|
|
const char *targetname;
|
|
ScriptVariable *var;
|
|
const char *value;
|
|
|
|
if ( ev->NumArgs() < 1 )
|
|
{
|
|
ev->Error( "Usage: spawn entityname [keyname] [value]..." );
|
|
return;
|
|
}
|
|
|
|
// create a new entity
|
|
SpawnArgs args;
|
|
|
|
name = ev->GetString( 1 );
|
|
|
|
if ( name )
|
|
{
|
|
cls = getClassForID( name );
|
|
if ( !cls )
|
|
{
|
|
cls = getClass( name );
|
|
}
|
|
|
|
if ( !cls )
|
|
{
|
|
str n;
|
|
|
|
n = name;
|
|
if ( !strstr( n.c_str(), ".tik" ) )
|
|
{
|
|
n += ".tik";
|
|
}
|
|
args.setArg( "model", n.c_str() );
|
|
}
|
|
else
|
|
{
|
|
args.setArg( "classname", name );
|
|
}
|
|
}
|
|
|
|
if ( ev->NumArgs() > 2 )
|
|
{
|
|
n = ev->NumArgs();
|
|
for( i = 2; i <= n; i += 2 )
|
|
{
|
|
args.setArg( ev->GetString( i ), ev->GetString( i + 1 ) );
|
|
}
|
|
}
|
|
|
|
cls = args.getClassDef();
|
|
if ( !cls )
|
|
{
|
|
ev->Error( "'%s' is not a valid entity name", name );
|
|
return;
|
|
}
|
|
|
|
// If there is a spawntarget set, then use that entity's origin and angles
|
|
targetname = args.getArg( "spawntarget" );
|
|
|
|
if ( targetname )
|
|
{
|
|
tent = G_FindTarget( NULL, targetname );
|
|
if ( tent )
|
|
{
|
|
args.setArg( "origin", va( "%f %f %f", tent->origin[ 0 ], tent->origin[ 1 ], tent->origin[ 2 ] ) );
|
|
args.setArg( "angle", va( "%f", tent->angles[1] ) );
|
|
}
|
|
else
|
|
{
|
|
ev->Error( "Can't find targetname %s", targetname );
|
|
}
|
|
}
|
|
|
|
//
|
|
// make sure to setup spawnflags properly
|
|
//
|
|
level.spawnflags = 0;
|
|
value = args.getArg( "spawnflags" );
|
|
if ( value )
|
|
{
|
|
level.spawnflags = atoi( value );
|
|
}
|
|
|
|
ent = args.Spawn();
|
|
if ( ent )
|
|
{
|
|
ent->ProcessPendingEvents();
|
|
}
|
|
var = Director.GetVariable( "parm.lastspawn" );
|
|
var->setIntValue( ent->entnum );
|
|
}
|
|
|
|
//FIXME
|
|
//Move this to someplace Level class.
|
|
static float last_fraction = 1.0f/8.0f;
|
|
|
|
void ScriptThread::Letterbox
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
level.m_letterbox_fraction = 1.0f/8.0f;
|
|
level.m_letterbox_time = ev->GetFloat( 1 );
|
|
level.m_letterbox_time_start = ev->GetFloat( 1 );
|
|
level.m_letterbox_dir = letterbox_in;
|
|
|
|
if ( ev->NumArgs() > 1 )
|
|
level.m_letterbox_fraction = ev->GetFloat( 2 );
|
|
}
|
|
|
|
void ScriptThread::ClearLetterbox
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
level.m_letterbox_time = level.m_letterbox_time_start;
|
|
level.m_letterbox_dir = letterbox_out;
|
|
}
|
|
|
|
void ScriptThread::SetDialogScript
|
|
(
|
|
Event *ev
|
|
)
|
|
{
|
|
ScriptThread * pThread;
|
|
|
|
ScriptLib.SetDialogScript( ev->GetString( 1 ) );
|
|
//
|
|
// precache the data in the dialog script
|
|
//
|
|
pThread = Director.CreateThread( &script, "dialog::precache" );
|
|
if ( pThread )
|
|
{
|
|
// start right away
|
|
pThread->Start( -1 );
|
|
}
|
|
}
|
|
|
|
void ScriptThread::SetLightStyle
|
|
(
|
|
Event *ev
|
|
)
|
|
{
|
|
lightStyles.SetLightStyle( ev->GetInteger( 1 ), ev->GetString( 2 ) );
|
|
}
|
|
|
|
void ScriptThread::FadeIn
|
|
(
|
|
Event *ev
|
|
)
|
|
{
|
|
level.m_fade_time_start = ev->GetFloat( 1 );
|
|
level.m_fade_time = ev->GetFloat( 1 );
|
|
level.m_fade_color[0] = ev->GetFloat( 2 );
|
|
level.m_fade_color[1] = ev->GetFloat( 3 );
|
|
level.m_fade_color[2] = ev->GetFloat( 4 );
|
|
level.m_fade_alpha = ev->GetFloat( 5 );
|
|
level.m_fade_type = fadein;
|
|
level.m_fade_style = alphablend;
|
|
|
|
if ( ev->NumArgs() > 5 )
|
|
{
|
|
level.m_fade_style = (fadestyle_t)ev->GetInteger( 6 );
|
|
}
|
|
}
|
|
|
|
void ScriptThread::ClearFade
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
level.m_fade_time = -1;
|
|
level.m_fade_type = fadein;
|
|
}
|
|
|
|
void ScriptThread::FadeOut
|
|
(
|
|
Event *ev
|
|
)
|
|
{
|
|
level.m_fade_time_start = ev->GetFloat( 1 );
|
|
level.m_fade_time = ev->GetFloat( 1 );
|
|
level.m_fade_color[0] = ev->GetFloat( 2 );
|
|
level.m_fade_color[1] = ev->GetFloat( 3 );
|
|
level.m_fade_color[2] = ev->GetFloat( 4 );
|
|
level.m_fade_alpha = ev->GetFloat( 5 );
|
|
level.m_fade_type = fadeout;
|
|
level.m_fade_style = alphablend;
|
|
|
|
if ( ev->NumArgs() > 5 )
|
|
{
|
|
level.m_fade_style = (fadestyle_t)ev->GetInteger( 6 );
|
|
}
|
|
}
|
|
|
|
void ScriptThread::FadeSound
|
|
(
|
|
Event *ev
|
|
)
|
|
{
|
|
G_FadeSound( ev->GetFloat( 1 ) );
|
|
}
|
|
|
|
void ScriptThread::MusicEvent
|
|
(
|
|
Event *ev
|
|
)
|
|
{
|
|
const char *current;
|
|
const char *fallback;
|
|
|
|
current = NULL;
|
|
fallback = NULL;
|
|
current = ev->GetString( 1 );
|
|
|
|
if ( ev->NumArgs() > 1 )
|
|
fallback = ev->GetString( 2 );
|
|
|
|
ChangeMusic( current, fallback, false );
|
|
}
|
|
|
|
void ScriptThread::MusicVolumeEvent
|
|
(
|
|
Event *ev
|
|
)
|
|
{
|
|
float volume;
|
|
float fade_time;
|
|
|
|
volume = ev->GetFloat( 1 );
|
|
fade_time = ev->GetFloat( 2 );
|
|
|
|
ChangeMusicVolume( volume, fade_time );
|
|
}
|
|
|
|
void ScriptThread::RestoreMusicVolumeEvent
|
|
(
|
|
Event *ev
|
|
)
|
|
{
|
|
float fade_time;
|
|
|
|
fade_time = ev->GetFloat( 1 );
|
|
|
|
RestoreMusicVolume( fade_time );
|
|
}
|
|
|
|
void ScriptThread::ForceMusicEvent
|
|
(
|
|
Event *ev
|
|
)
|
|
{
|
|
const char *current;
|
|
const char *fallback;
|
|
|
|
current = NULL;
|
|
fallback = NULL;
|
|
current = ev->GetString( 1 );
|
|
|
|
if ( ev->NumArgs() > 1 )
|
|
fallback = ev->GetString( 2 );
|
|
|
|
ChangeMusic( current, fallback, true );
|
|
}
|
|
|
|
void ScriptThread::SoundtrackEvent
|
|
(
|
|
Event *ev
|
|
)
|
|
{
|
|
ChangeSoundtrack( ev->GetString( 1 ) );
|
|
}
|
|
|
|
void ScriptThread::RestoreSoundtrackEvent
|
|
(
|
|
Event *ev
|
|
)
|
|
{
|
|
RestoreSoundtrack();
|
|
}
|
|
|
|
void ScriptThread::SetCinematic
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
G_StartCinematic();
|
|
}
|
|
|
|
void ScriptThread::SetNonCinematic
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
G_StopCinematic();
|
|
}
|
|
|
|
void ScriptThread::SetAllAIOff
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
level.ai_on = false;
|
|
}
|
|
|
|
void ScriptThread::SetAllAIOn
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
level.ai_on = true;
|
|
}
|
|
|
|
void ScriptThread::SetSkipThread
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
str label;
|
|
|
|
label = ev->GetString( 1 );
|
|
if ( label.length() && label.icmp( "null" ) )
|
|
{
|
|
world->skipthread = script.Filename() + str( "::" ) + label;
|
|
}
|
|
else
|
|
{
|
|
world->skipthread = "";
|
|
}
|
|
}
|
|
|
|
void ScriptThread::KillThreadEvent
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
Director.KillThread( ev->GetString( 1 ) );
|
|
}
|
|
|
|
void ScriptThread::PassToPathmanager
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
PathManager.ProcessEvent( ev );
|
|
}
|
|
|
|
void ScriptThread::CenterPrint
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
int j;
|
|
gentity_t *other;
|
|
|
|
for( j = 0; j < game.maxclients; j++ )
|
|
{
|
|
other = &g_entities[ j ];
|
|
if ( other->inuse && other->client )
|
|
{
|
|
gi.centerprintf( other, ev->GetString( 1 ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
void ScriptThread::LocationPrint
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
int j;
|
|
gentity_t *other;
|
|
int x,y;
|
|
|
|
x = ev->GetInteger( 1 );
|
|
y = ev->GetInteger( 2 );
|
|
|
|
for( j = 0; j < game.maxclients; j++ )
|
|
{
|
|
other = &g_entities[ j ];
|
|
if ( other->inuse && other->client )
|
|
{
|
|
gi.locationprintf( other, x, y, ev->GetString( 3 ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
void ScriptThread::StuffCommand
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
gi.SendConsoleCommand( va( "%s\n", ev->GetString( 1 ) ) );
|
|
}
|
|
|
|
void ScriptThread::KillEnt
|
|
(
|
|
Event * ev
|
|
)
|
|
{
|
|
int num;
|
|
Entity *ent;
|
|
|
|
if ( ev->NumArgs() != 1 )
|
|
{
|
|
ev->Error( "No args passed in" );
|
|
return;
|
|
}
|
|
|
|
num = ev->GetInteger( 1 );
|
|
if ( ( num < 0 ) || ( num >= globals.max_entities ) )
|
|
{
|
|
ev->Error( "Value out of range. Possible values range from 0 to %d.\n", globals.max_entities );
|
|
return;
|
|
}
|
|
|
|
ent = G_GetEntity( num );
|
|
ent->Damage( world, world, ent->max_health + 25, vec_zero, vec_zero, vec_zero, 0, 0, 0 );
|
|
}
|
|
|
|
void ScriptThread::RemoveEnt
|
|
(
|
|
Event * ev
|
|
)
|
|
{
|
|
int num;
|
|
Entity *ent;
|
|
|
|
if ( ev->NumArgs() != 1 )
|
|
{
|
|
ev->Error( "No args passed in" );
|
|
return;
|
|
}
|
|
|
|
num = ev->GetInteger( 1 );
|
|
if ( ( num < 0 ) || ( num >= globals.max_entities ) )
|
|
{
|
|
ev->Error( "Value out of range. Possible values range from 0 to %d.\n", globals.max_entities );
|
|
return;
|
|
}
|
|
|
|
ent = G_GetEntity( num );
|
|
ent->PostEvent( Event( EV_Remove ), 0 );
|
|
}
|
|
|
|
void ScriptThread::KillClass
|
|
(
|
|
Event * ev
|
|
)
|
|
{
|
|
int except;
|
|
str classname;
|
|
gentity_t * from;
|
|
Entity *ent;
|
|
|
|
if ( ev->NumArgs() < 1 )
|
|
{
|
|
ev->Error( "No args passed in" );
|
|
return;
|
|
}
|
|
|
|
classname = ev->GetString( 1 );
|
|
|
|
except = 0;
|
|
if ( ev->NumArgs() == 2 )
|
|
{
|
|
except = ev->GetInteger( 1 );
|
|
}
|
|
|
|
for ( from = &g_entities[ game.maxclients ]; from < &g_entities[ globals.num_entities ]; from++ )
|
|
{
|
|
if ( !from->inuse )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
assert( from->entity );
|
|
|
|
ent = from->entity;
|
|
|
|
if ( ent->entnum == except )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( ent->inheritsFrom( classname.c_str() ) )
|
|
{
|
|
ent->Damage( world, world, ent->max_health + 25, vec_zero, vec_zero, vec_zero, 0, 0, 0 );
|
|
}
|
|
}
|
|
}
|
|
|
|
void ScriptThread::RemoveClass
|
|
(
|
|
Event * ev
|
|
)
|
|
{
|
|
int except;
|
|
str classname;
|
|
gentity_t * from;
|
|
Entity *ent;
|
|
|
|
if ( ev->NumArgs() < 1 )
|
|
{
|
|
ev->Error( "No args passed in" );
|
|
return;
|
|
}
|
|
|
|
classname = ev->GetString( 1 );
|
|
|
|
except = 0;
|
|
if ( ev->NumArgs() == 2 )
|
|
{
|
|
except = ev->GetInteger( 1 );
|
|
}
|
|
|
|
for ( from = &g_entities[ game.maxclients ]; from < &g_entities[ globals.num_entities ]; from++ )
|
|
{
|
|
if ( !from->inuse )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
assert( from->entity );
|
|
|
|
ent = from->entity;
|
|
|
|
if ( ent->entnum == except )
|
|
continue;
|
|
|
|
if ( ent->inheritsFrom( classname.c_str() ) )
|
|
{
|
|
ent->PostEvent( Event( EV_Remove ), 0 );
|
|
}
|
|
}
|
|
}
|
|
|
|
void ScriptThread::CameraCommand
|
|
(
|
|
Event * ev
|
|
)
|
|
|
|
{
|
|
Event *e;
|
|
const char *cmd;
|
|
int i;
|
|
int n;
|
|
|
|
if ( !ev->NumArgs() )
|
|
{
|
|
ev->Error( "Usage: cam [command] [arg 1]...[arg n]" );
|
|
return;
|
|
}
|
|
|
|
cmd = ev->GetString( 1 );
|
|
if ( Event::Exists( cmd ) )
|
|
{
|
|
e = new Event( cmd );
|
|
e->SetSource( EV_FROM_SCRIPT );
|
|
e->SetThread( this );
|
|
e->SetLineNumber( linenumber );
|
|
|
|
n = ev->NumArgs();
|
|
for( i = 2; i <= n; i++ )
|
|
{
|
|
e->AddToken( ev->GetToken( i ) );
|
|
}
|
|
|
|
CameraMan.ProcessEvent( e );
|
|
}
|
|
else
|
|
{
|
|
ev->Error( "Unknown camera command '%s'.\n", cmd );
|
|
}
|
|
}
|
|
|
|
void ScriptThread::MissionFailed
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
G_MissionFailed();
|
|
}
|
|
|
|
void ScriptThread::ArenaCommand
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
// Make sure we are in arena mode for this command
|
|
|
|
if ( g_gametype->integer == GT_ARENA )
|
|
{
|
|
dmManager.ArenaCommand( ev );
|
|
}
|
|
else
|
|
{
|
|
warning( "ScriptThread::ArenaCommand", "Arena mode not set, ignoring arena command.\n" );
|
|
}
|
|
} */
|
|
|
|
////////////////////////
|
|
//
|
|
// LIGHTSTYLE REPOSITORY
|
|
//
|
|
////////////////////////
|
|
|
|
LightStyleClass lightStyles;
|
|
|
|
CLASS_DECLARATION( Class, LightStyleClass, NULL )
|
|
{
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
void LightStyleClass::SetLightStyle( int index, const str &style )
|
|
{
|
|
if ( ( index < 0 ) || ( index >= MAX_LIGHTSTYLES ) )
|
|
{
|
|
assert( 0 );
|
|
return;
|
|
}
|
|
|
|
styles[ index ] = style;
|
|
gi.SetLightStyle( index, style.c_str() );
|
|
}
|
|
|
|
void LightStyleClass::Archive( Archiver &arc )
|
|
{
|
|
int i;
|
|
|
|
for( i = 0; i < MAX_LIGHTSTYLES; i++ )
|
|
{
|
|
arc.ArchiveString( &styles[ i ] );
|
|
if ( arc.Loading() && styles[ i ].length() )
|
|
{
|
|
gi.SetLightStyle( i, styles[ i ].c_str() );
|
|
}
|
|
}
|
|
}
|