📄 listener.cpp
字号:
//-----------------------------------------------------------------------------
//
// $Logfile:: /Quake 2 Engine/Sin/code/game/listener.cpp $
// $Revision:: 45 $
// $Author:: Jimdose $
// $Date:: 11/10/98 5:48p $
//
// Copyright (C) 1998 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.
//
// $Log:: /Quake 2 Engine/Sin/code/game/listener.cpp $
//
// 45 11/10/98 5:48p Jimdose
// Made SortEventList sort the list manually when TEMPLATE_EXPORT is not
// defined
//
// 44 10/26/98 4:27p Jimdose
// Sped up ValidEvent
// Added FindEvent( const char * )
//
// 43 10/24/98 3:25a Jimdose
// added g_watch for only displaying events from a specific object
//
// 42 10/19/98 6:30p Jimdose
// increased g_eventlimit to 1500
//
// 41 10/19/98 12:07a Jimdose
// made all code use fast checks for inheritance (no text lookups when
// possible)
// isSubclassOf no longer requires ::_classinfo()
//
// 40 10/18/98 8:44p Jimdose
// Made commandList a Container of str * instead of str. Fixes problem of name
// pointer in event being invalidated when commandList is resized
//
// 39 10/18/98 3:22a Jimdose
// Added code for timing events
//
// 38 10/17/98 11:33p Jimdose
// Added the event name to Event to help with debugging
//
// 37 10/17/98 12:22a Jimdose
// upped g_eventlimit to 500
//
// 36 10/16/98 7:19p Jimdose
// Added g_eventlimit
// G_ProcessPendingEvents now breaks out if the number of events executed
// during the call exceeds g_eventlimit.
// Removed g_response and old code from ProcessEvent
//
// 35 10/16/98 1:53a Jimdose
// Added FL_DONTSAVE to entities, so events that belong to entities with this
// flag aren't archived
//
// 34 10/10/98 1:28a Jimdose
// PostEvent kills any events posted during a loadgame
//
// 33 10/07/98 11:52p Jimdose
// Wrote Event archiving functions
//
// 32 9/24/98 1:46a Jimdose
// Made Event a subclass of Class
//
// 31 9/19/98 4:32p Jimdose
// Added ListCommands
//
// 30 8/27/98 9:03p Jimdose
// Moved a lot of small functions to the header as inline
//
// 29 8/26/98 6:42p Jimdose
// Added more info when g_showevents is set
//
// 28 8/20/98 4:42p Jimdose
// (Finally) added binary search for resolving event names
//
// 27 8/17/98 4:29p Jimdose
// added event reporting with g_showevents cvar
//
// 26 8/06/98 5:18p Jimdose
// Fixed check for default flags in Event constructor for str objects
//
// 25 8/01/98 7:58p Jimdose
// Fixed bug with cheats in dm
//
// 24 7/31/98 8:09p Jimdose
// Script commands now include flags to indicate cheats and console commands
//
// 23 7/31/98 4:19p Jimdose
// Added DepthOfEvent
//
// 22 7/20/98 5:09p Jimdose
// Added ProcessPendingEvents
//
// 21 7/10/98 10:00p Jimdose
// Made remove script command post remove event so that it doesn't cause
// problems during event callbacks which trigger the script
//
// 20 7/08/98 12:54p Jimdose
// Made error for vectors not including '(' ')' a developer 2 warning
//
// 19 6/30/98 6:05p Jimdose
// Added IsVectorAt, IsEntityAt, and IsNumericAt for doing type checking on
// args
// Changed format for storing vectors to make it easy to identify
//
// 18 6/27/98 9:18p Jimdose
// Made lookup for event responses for faster processing
//
// 17 6/24/98 6:48p Jimdose
// Made entity number based commands use "*" prefix consistantly
//
// 16 6/20/98 7:41p Jimdose
// Made GetEntity return NULL if the index is out of range
//
// 15 6/18/98 8:47p Jimdose
// Added better event error handling
// Added source info to events
// Added checks for event still in use when processing events (prevents
// deleting events twice)
//
// 14 6/17/98 3:03p Markd
// Changed NumArgs back to previous behavior
//
// 13 6/10/98 7:53p Markd
// Made NumArgs behave correctly like argc
//
// 12 5/24/98 8:46p Jimdose
// Made a lot of functions more str-friendly.
// Got rid of a lot of char * based strings
// Cleaned up get spawn arg functions and sound functions
// sound functions now use consistant syntax
//
// 11 5/24/98 4:48p Jimdose
// Made char *'s const
//
// 10 5/24/98 1:06a Jimdose
// added const to various char *s
//
// 9 5/08/98 2:51p Jimdose
// Moved archiving functions up to Class
//
// 8 5/07/98 10:42p Jimdose
// Added archive and unarchive
//
// 7 4/30/98 9:24p Jimdose
// Changed use of string to str class
//
// 6 4/06/98 5:44p Jimdose
// Added assertion for null entities in AddEntity. In the release version, it
// "safely" treats null ents as entnum 0
//
// 5 4/02/98 4:48p Jimdose
// Added initCommandList to ensure that NullEvent is always initialized first
//
// 4 3/24/98 5:02p Jimdose
// Made GetToken return the exact string instead of resolving the value of
// variables
// PostponeEvent was not updating the position of the event in the list, which
// would cause a logjam of events that were following the event.
//
// 3 3/23/98 1:31p Jimdose
// Revamped event and command system
//
// 2 3/04/98 1:01p Jimdose
// Created file
//
// DESCRIPTION:
//
#include "listener.h"
#include "scriptvariable.h"
#include "worldspawn.h"
#include "scriptmaster.h"
Event EV_Remove( "immediateremove" );
Event EV_ScriptRemove( "remove" );
typedef struct eventcache_s
{
Listener *obj;
Event *event;
float time;
struct eventcache_s *next;
struct eventcache_s *prev;
} eventcache_t;
#define MAX_EVENTS 2000
extern "C"
{
eventcache_t Events[ MAX_EVENTS ];
int numEvents = 0;
cvar_t *g_numevents;
};
cvar_t *g_showevents;
cvar_t *g_eventlimit;
cvar_t *g_timeevents;
cvar_t *g_watch;
eventcache_t FreeEventHead;
eventcache_t *FreeEvents = &FreeEventHead;
eventcache_t EventQueueHead;
eventcache_t *EventQueue = &EventQueueHead;
Container<str *> *Event::commandList = NULL;
Container<int> *Event::flagList = NULL;
Container<int> *Event::sortedList = NULL;
qboolean Event::dirtylist = false;
Event NullEvent;
CLASS_DECLARATION( Class, Event, NULL );
ResponseDef Event::Responses[] =
{
{ NULL, NULL }
};
EXPORT_FROM_DLL int Event::NumEventCommands
(
void
)
{
if ( commandList )
{
// Add 1 since container gives the inclusive number of objects
return commandList->NumObjects() + 1;
}
return 0;
}
EXPORT_FROM_DLL int Event::compareEvents
(
const void *arg1,
const void *arg2
)
{
int ev1;
int ev2;
ev1 = *( int * )arg1;
ev2 = *( int * )arg2;
return stricmp( commandList->ObjectAt( ev1 )->c_str(), commandList->ObjectAt( ev2 )->c_str() );
}
EXPORT_FROM_DLL void Event::SortEventList
(
void
)
{
dirtylist = false;
if ( sortedList && commandList )
{
#ifndef EXPORT_TEMPLATE
qsort( ( void * )sortedList->AddressOfObjectAt( 1 ),
( size_t )sortedList->NumObjects(),
sizeof( int ), compareEvents );
#else
sortedList->Sort( compareEvents );
#endif
}
}
inline EXPORT_FROM_DLL int Event::FindEvent
(
const char *name
)
{
int eventnum;
int index;
int l;
int r;
int diff;
assert( name );
if ( !name )
{
return 0;
}
if ( !commandList )
{
return 0;
}
if ( dirtylist )
{
SortEventList();
}
l = 1;
r = sortedList->NumObjects();
while( r >= l )
{
index = ( l + r ) >> 1;
eventnum = sortedList->ObjectAt( index );
diff = stricmp( name, commandList->ObjectAt( eventnum )->c_str() );
if ( diff < 0 )
{
r = index - 1;
}
else if ( diff > 0 )
{
l = index + 1;
}
else
{
return eventnum;
}
}
return 0;
}
EXPORT_FROM_DLL int Event::FindEvent
(
str &name
)
{
return FindEvent( name.c_str() );
}
EXPORT_FROM_DLL void Event::ListCommands
(
const char *mask
)
{
str name;
int flags;
int eventnum;
int num;
int i;
int n;
int l;
int p;
int hidden;
str text;
if ( !commandList )
{
gi.printf( "No events.\n" );
return;
}
if ( dirtylist )
{
SortEventList();
}
l = 0;
if ( mask )
{
l = strlen( mask );
}
hidden = 0;
num = 0;
n = sortedList->NumObjects();
for( i = 1; i <= n; i++ )
{
eventnum = sortedList->ObjectAt( i );
name = commandList->ObjectAt( eventnum )->c_str();
flags = flagList->ObjectAt( eventnum );
if ( flags & EV_HIDE )
{
hidden++;
continue;
}
if ( mask && Q_strncasecmp( name.c_str(), mask, l ) )
{
continue;
}
num++;
text = " ";
p = 0;
if ( flags & EV_CONSOLE )
{
text[ p++ ] = '*';
}
if ( flags & EV_CHEAT )
{
text[ p++ ] = 'C';
}
gi.printf( "%4d : %s%s\n", eventnum, text.c_str(), name.c_str() );
}
gi.printf( "\n* = console command.\nC = cheat command.\n\n"
"Printed %d of %d total commands.\n", num, n - hidden );
if ( developer->value && hidden )
{
gi.printf( "Suppressed %d commands.\n", hidden );
}
}
EXPORT_FROM_DLL void Event::initCommandList
(
void
)
{
int flags;
str *n;
flags = 0;
commandList = new Container<str *>;
n = new str( "NULL" );
NullEvent.eventnum = commandList->AddObject( n );
flagList = new Container<int>;
flagList->AddObject( flags );
sortedList = new Container<int>;
sortedList->AddObject( NullEvent.eventnum );
dirtylist = false;
NullEvent.data = NULL;
NullEvent.info.inuse = 0;
NullEvent.info.source = EV_FROM_CODE;
NullEvent.info.flags = 0;
NullEvent.info.linenumber = 0;
}
Event::Event()
{
info.inuse = 0;
info.source = EV_FROM_CODE;
info.flags = 0;
info.linenumber = 0;
threadnum = -1;
eventnum = 0;
data = NULL;
name = NULL;
}
Event::Event
(
int num
)
{
if ( !commandList )
{
initCommandList();
}
assert( ( num > 0 ) && num <= commandList->NumObjects() );
if ( ( num <= 0 ) || ( num > commandList->NumObjects() ) )
{
num = 0;
name = NULL;
info.flags = 0;
}
else
{
name = commandList->ObjectAt( num )->c_str();
info.flags = flagList->ObjectAt( num );
}
eventnum = num;
data = NULL;
info.inuse = 0;
info.source = EV_FROM_CODE;
info.linenumber = 0;
threadnum = -1;
}
Event::Event
(
Event &ev
)
{
int num;
int i;
eventnum = ( int )ev;
assert( ( eventnum > 0 ) && eventnum <= commandList->NumObjects() );
data = NULL;
name = commandList->ObjectAt( eventnum )->c_str();
info.inuse = 0;
info.source = ev.info.source;
info.flags = ev.info.flags;
info.linenumber = ev.info.linenumber;
threadnum = ev.threadnum;
if ( ev.data )
{
num = ev.data->NumObjects();
data = new Container<str>;
data->Resize( num );
for( i = 1; i <= num; i++ )
{
data->AddObject( ev.data->ObjectAt( i ) );
}
}
}
Event::Event
(
Event *ev
)
{
int num;
int i;
assert( ev );
if ( !ev )
{
Class::error( "Event", "NULL Event\n" );
}
eventnum = ( int )*ev;
assert( ( eventnum > 0 ) && eventnum <= commandList->NumObjects() );
data = NULL;
name = commandList->ObjectAt( eventnum )->c_str();
info.inuse = 0;
info.source = ev->info.source;
info.flags = ev->info.flags;
info.linenumber = ev->info.linenumber;
threadnum = ev->threadnum;
if ( ev->data )
{
num = ev->data->NumObjects();
data = new Container<str>;
data->Resize( num );
for( i = 1; i <= num; i++ )
{
data->AddObject( ev->data->ObjectAt( i ) );
}
}
}
Event::Event
(
const char *command,
int flags
)
{
str c;
str *t;
if ( !commandList )
{
initCommandList();
}
c = command;
eventnum = FindEvent( c );
if ( !eventnum )
{
t = new str( c );
eventnum = commandList->AddObject( t );
// check for default flags
if ( flags == -1 )
{
flags = 0;
}
flagList->AddObject( ( int )flags );
sortedList->AddObject( eventnum );
dirtylist = true;
}
// Use the name stored in the command list in case the string passed in
// is not in static memory.
name = commandList->ObjectAt( eventnum )->c_str();
data = NULL;
info.inuse = 0;
info.source = EV_FROM_CODE;
info.linenumber = 0;
threadnum = -1;
// If flags have changed, let the user know. It's probably a development bug.
int &flagobj = flagList->ObjectAt( eventnum );
// check for default flags
if ( flags == -1 )
{
flags = flagobj;
}
assert( flags == flagobj );
if ( flags != flagobj )
{
// Flags not equal. Use combined value.
flagobj |= flags;
}
info.flags = flagobj;
}
Event::Event
(
str &command,
int flags
)
{
str *t;
if ( !commandList )
{
initCommandList();
}
eventnum = FindEvent( command );
if ( !eventnum )
{
t = new str( command );
eventnum = commandList->AddObject( t );
// check for default flags
if ( flags == -1 )
{
flags = 0;
}
flagList->AddObject( flags );
sortedList->AddObject( eventnum );
dirtylist = true;
}
// Use the name stored in the command list since the string passed in
// is not in static memory.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -