2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
26 ===========================================================================
31 Event are used for scheduling tasks and for linking script commands.
35 #include "../../idlib/precompiled.h"
38 #include "../Game_local.h"
40 #define MAX_EVENTSPERFRAME 4096
41 //#define CREATE_EVENT_CODE
43 /***********************************************************************
47 ***********************************************************************/
49 idEventDef *idEventDef::eventDefList[MAX_EVENTS];
50 int idEventDef::numEventDefs = 0;
52 static bool eventError = false;
53 static char eventErrorMsg[ 128 ];
57 idEventDef::idEventDef
60 idEventDef::idEventDef( const char *command, const char *formatspec, char returnType ) {
66 assert( !idEvent::initialized );
68 // Allow NULL to indicate no args, but always store it as ""
69 // so we don't have to check for it.
75 this->formatspec = formatspec;
76 this->returnType = returnType;
78 numargs = strlen( formatspec );
79 assert( numargs <= D_EVENT_MAXARGS );
80 if ( numargs > D_EVENT_MAXARGS ) {
82 sprintf( eventErrorMsg, "idEventDef::idEventDef : Too many args for '%s' event.", name );
86 // make sure the format for the args is valid, calculate the formatspecindex, and the offsets for each arg
89 memset( argOffset, 0, sizeof( argOffset ) );
90 for( i = 0; i < numargs;i++ ) {
91 argOffset[ i ] = argsize;
92 switch( formatspec[ i ] ) {
95 argsize += sizeof( float );
98 case D_EVENT_INTEGER :
99 argsize += sizeof( int );
102 case D_EVENT_VECTOR :
103 argsize += sizeof( idVec3 );
106 case D_EVENT_STRING :
107 argsize += MAX_STRING_LEN;
110 case D_EVENT_ENTITY :
111 argsize += sizeof( idEntityPtr<idEntity> );
114 case D_EVENT_ENTITY_NULL :
115 argsize += sizeof( idEntityPtr<idEntity> );
119 argsize += sizeof( trace_t ) + MAX_STRING_LEN + sizeof( bool );
124 sprintf( eventErrorMsg, "idEventDef::idEventDef : Invalid arg format '%s' string for '%s' event.", formatspec, name );
130 // calculate the formatspecindex
131 formatspecIndex = ( 1 << ( numargs + D_EVENT_MAXARGS ) ) | bits;
133 // go through the list of defined events and check for duplicates
134 // and mismatched format strings
135 eventnum = numEventDefs;
136 for( i = 0; i < eventnum; i++ ) {
137 ev = eventDefList[ i ];
138 if ( strcmp( command, ev->name ) == 0 ) {
139 if ( strcmp( formatspec, ev->formatspec ) != 0 ) {
141 sprintf( eventErrorMsg, "idEvent '%s' defined twice with same name but differing format strings ('%s'!='%s').",
142 command, formatspec, ev->formatspec );
146 if ( ev->returnType != returnType ) {
148 sprintf( eventErrorMsg, "idEvent '%s' defined twice with same name but differing return types ('%c'!='%c').",
149 command, returnType, ev->returnType );
152 // Don't bother putting the duplicate event in list.
153 eventnum = ev->eventnum;
160 if ( numEventDefs >= MAX_EVENTS ) {
162 sprintf( eventErrorMsg, "numEventDefs >= MAX_EVENTS" );
165 eventDefList[numEventDefs] = ev;
171 idEventDef::NumEventCommands
174 int idEventDef::NumEventCommands( void ) {
180 idEventDef::GetEventCommand
183 const idEventDef *idEventDef::GetEventCommand( int eventnum ) {
184 return eventDefList[ eventnum ];
189 idEventDef::FindEvent
192 const idEventDef *idEventDef::FindEvent( const char *name ) {
200 for( i = 0; i < num; i++ ) {
201 ev = eventDefList[ i ];
202 if ( strcmp( name, ev->name ) == 0 ) {
210 /***********************************************************************
214 ***********************************************************************/
216 static idLinkList<idEvent> FreeEvents;
217 static idLinkList<idEvent> EventQueue;
219 static idLinkList<idEvent> FastEventQueue;
221 static idEvent EventPool[ MAX_EVENTS ];
223 bool idEvent::initialized = false;
225 idDynamicBlockAlloc<byte, 16 * 1024, 256> idEvent::eventDataAllocator;
232 idEvent::~idEvent() {
241 idEvent *idEvent::Alloc( const idEventDef *evdef, int numargs, va_list args ) {
248 const char *materialName;
250 if ( FreeEvents.IsListEmpty() ) {
251 gameLocal.Error( "idEvent::Alloc : No more free events" );
254 ev = FreeEvents.Next();
255 ev->eventNode.Remove();
257 ev->eventdef = evdef;
259 if ( numargs != evdef->GetNumArgs() ) {
260 gameLocal.Error( "idEvent::Alloc : Wrong number of args for '%s' event.", evdef->GetName() );
263 size = evdef->GetArgSize();
265 ev->data = eventDataAllocator.Alloc( size );
266 memset( ev->data, 0, size );
271 format = evdef->GetArgFormat();
272 for( i = 0; i < numargs; i++ ) {
273 arg = va_arg( args, idEventArg * );
274 if ( format[ i ] != arg->type ) {
275 // when NULL is passed in for an entity, it gets cast as an integer 0, so don't give an error when it happens
276 if ( !( ( ( format[ i ] == D_EVENT_TRACE ) || ( format[ i ] == D_EVENT_ENTITY ) ) && ( arg->type == 'd' ) && ( arg->value == 0 ) ) ) {
277 gameLocal.Error( "idEvent::Alloc : Wrong type passed in for arg # %d on '%s' event.", i, evdef->GetName() );
281 dataPtr = &ev->data[ evdef->GetArgOffset( i ) ];
283 switch( format[ i ] ) {
285 case D_EVENT_INTEGER :
286 *reinterpret_cast<int *>( dataPtr ) = arg->value;
289 case D_EVENT_VECTOR :
291 *reinterpret_cast<idVec3 *>( dataPtr ) = *reinterpret_cast<const idVec3 *>( arg->value );
295 case D_EVENT_STRING :
297 idStr::Copynz( reinterpret_cast<char *>( dataPtr ), reinterpret_cast<const char *>( arg->value ), MAX_STRING_LEN );
301 case D_EVENT_ENTITY :
302 case D_EVENT_ENTITY_NULL :
303 *reinterpret_cast< idEntityPtr<idEntity> * >( dataPtr ) = reinterpret_cast<idEntity *>( arg->value );
308 *reinterpret_cast<bool *>( dataPtr ) = true;
309 *reinterpret_cast<trace_t *>( dataPtr + sizeof( bool ) ) = *reinterpret_cast<const trace_t *>( arg->value );
311 // save off the material as a string since the pointer won't be valid in save games.
312 // since we save off the entire trace_t structure, if the material is NULL here,
313 // it will be NULL when we process it, so we don't need to save off anything in that case.
314 if ( reinterpret_cast<const trace_t *>( arg->value )->c.material ) {
315 materialName = reinterpret_cast<const trace_t *>( arg->value )->c.material->GetName();
316 idStr::Copynz( reinterpret_cast<char *>( dataPtr + sizeof( bool ) + sizeof( trace_t ) ), materialName, MAX_STRING_LEN );
319 *reinterpret_cast<bool *>( dataPtr ) = false;
324 gameLocal.Error( "idEvent::Alloc : Invalid arg format '%s' string for '%s' event.", format, evdef->GetName() );
337 void idEvent::CopyArgs( const idEventDef *evdef, int numargs, va_list args, int data[ D_EVENT_MAXARGS ] ) {
342 format = evdef->GetArgFormat();
343 if ( numargs != evdef->GetNumArgs() ) {
344 gameLocal.Error( "idEvent::CopyArgs : Wrong number of args for '%s' event.", evdef->GetName() );
347 for( i = 0; i < numargs; i++ ) {
348 arg = va_arg( args, idEventArg * );
349 if ( format[ i ] != arg->type ) {
350 // when NULL is passed in for an entity, it gets cast as an integer 0, so don't give an error when it happens
351 if ( !( ( ( format[ i ] == D_EVENT_TRACE ) || ( format[ i ] == D_EVENT_ENTITY ) ) && ( arg->type == 'd' ) && ( arg->value == 0 ) ) ) {
352 gameLocal.Error( "idEvent::CopyArgs : Wrong type passed in for arg # %d on '%s' event.", i, evdef->GetName() );
356 data[ i ] = arg->value;
365 void idEvent::Free( void ) {
367 eventDataAllocator.Free( data );
376 eventNode.SetOwner( this );
377 eventNode.AddToEnd( FreeEvents );
385 void idEvent::Schedule( idClass *obj, const idTypeInfo *type, int time ) {
388 assert( initialized );
389 if ( !initialized ) {
396 // wraps after 24 days...like I care. ;)
397 this->time = gameLocal.time + time;
402 if ( obj->IsType( idEntity::Type ) && ( ( (idEntity*)(obj) )->timeGroup == TIME_GROUP2 ) ) {
403 event = FastEventQueue.Next();
404 while( ( event != NULL ) && ( this->time >= event->time ) ) {
405 event = event->eventNode.Next();
409 eventNode.InsertBefore( event->eventNode );
411 eventNode.AddToEnd( FastEventQueue );
416 this->time = gameLocal.slow.time + time;
420 event = EventQueue.Next();
421 while( ( event != NULL ) && ( this->time >= event->time ) ) {
422 event = event->eventNode.Next();
426 eventNode.InsertBefore( event->eventNode );
428 eventNode.AddToEnd( EventQueue );
434 idEvent::CancelEvents
437 void idEvent::CancelEvents( const idClass *obj, const idEventDef *evdef ) {
441 if ( !initialized ) {
445 for( event = EventQueue.Next(); event != NULL; event = next ) {
446 next = event->eventNode.Next();
447 if ( event->object == obj ) {
448 if ( !evdef || ( evdef == event->eventdef ) ) {
455 for( event = FastEventQueue.Next(); event != NULL; event = next ) {
456 next = event->eventNode.Next();
457 if ( event->object == obj ) {
458 if ( !evdef || ( evdef == event->eventdef ) ) {
468 idEvent::ClearEventList
471 void idEvent::ClearEventList( void ) {
481 // add the events to the free list
483 for( i = 0; i < MAX_EVENTS; i++ ) {
484 EventPool[ i ].Free();
490 idEvent::ServiceEvents
493 void idEvent::ServiceEvents( void ) {
496 int args[ D_EVENT_MAXARGS ];
500 const char *formatspec;
502 const idEventDef *ev;
504 const char *materialName;
507 while( !EventQueue.IsListEmpty() ) {
508 event = EventQueue.Next();
511 if ( event->time > gameLocal.time ) {
515 // copy the data into the local args array and set up pointers
516 ev = event->eventdef;
517 formatspec = ev->GetArgFormat();
518 numargs = ev->GetNumArgs();
519 for( i = 0; i < numargs; i++ ) {
520 offset = ev->GetArgOffset( i );
522 switch( formatspec[ i ] ) {
524 case D_EVENT_INTEGER :
525 args[ i ] = *reinterpret_cast<int *>( &data[ offset ] );
528 case D_EVENT_VECTOR :
529 *reinterpret_cast<idVec3 **>( &args[ i ] ) = reinterpret_cast<idVec3 *>( &data[ offset ] );
532 case D_EVENT_STRING :
533 *reinterpret_cast<const char **>( &args[ i ] ) = reinterpret_cast<const char *>( &data[ offset ] );
536 case D_EVENT_ENTITY :
537 case D_EVENT_ENTITY_NULL :
538 *reinterpret_cast<idEntity **>( &args[ i ] ) = reinterpret_cast< idEntityPtr<idEntity> * >( &data[ offset ] )->GetEntity();
542 tracePtr = reinterpret_cast<trace_t **>( &args[ i ] );
543 if ( *reinterpret_cast<bool *>( &data[ offset ] ) ) {
544 *tracePtr = reinterpret_cast<trace_t *>( &data[ offset + sizeof( bool ) ] );
546 if ( ( *tracePtr )->c.material != NULL ) {
547 // look up the material name to get the material pointer
548 materialName = reinterpret_cast<const char *>( &data[ offset + sizeof( bool ) + sizeof( trace_t ) ] );
549 ( *tracePtr )->c.material = declManager->FindMaterial( materialName, true );
557 gameLocal.Error( "idEvent::ServiceEvents : Invalid arg format '%s' string for '%s' event.", formatspec, ev->GetName() );
561 // the event is removed from its list so that if then object
562 // is deleted, the event won't be freed twice
563 event->eventNode.Remove();
564 assert( event->object );
565 event->object->ProcessEventArgPtr( ev, args );
568 // event functions may never leave return values on the FPU stack
569 // enable this code to check if any event call left values on the FPU stack
570 if ( !sys->FPU_StackIsEmpty() ) {
571 gameLocal.Error( "idEvent::ServiceEvents %d: %s left a value on the FPU stack\n", num, ev->GetName() );
575 // return the event to the free list
578 // Don't allow ourselves to stay in here too long. An abnormally high number
579 // of events being processed is evidence of an infinite loop of events.
581 if ( num > MAX_EVENTSPERFRAME ) {
582 gameLocal.Error( "Event overflow. Possible infinite loop in script." );
590 idEvent::ServiceFastEvents
593 void idEvent::ServiceFastEvents() {
596 int args[ D_EVENT_MAXARGS ];
600 const char *formatspec;
602 const idEventDef *ev;
604 const char *materialName;
607 while( !FastEventQueue.IsListEmpty() ) {
608 event = FastEventQueue.Next();
611 if ( event->time > gameLocal.fast.time ) {
615 // copy the data into the local args array and set up pointers
616 ev = event->eventdef;
617 formatspec = ev->GetArgFormat();
618 numargs = ev->GetNumArgs();
619 for( i = 0; i < numargs; i++ ) {
620 offset = ev->GetArgOffset( i );
622 switch( formatspec[ i ] ) {
624 case D_EVENT_INTEGER :
625 args[ i ] = *reinterpret_cast<int *>( &data[ offset ] );
628 case D_EVENT_VECTOR :
629 *reinterpret_cast<idVec3 **>( &args[ i ] ) = reinterpret_cast<idVec3 *>( &data[ offset ] );
632 case D_EVENT_STRING :
633 *reinterpret_cast<const char **>( &args[ i ] ) = reinterpret_cast<const char *>( &data[ offset ] );
636 case D_EVENT_ENTITY :
637 case D_EVENT_ENTITY_NULL :
638 *reinterpret_cast<idEntity **>( &args[ i ] ) = reinterpret_cast< idEntityPtr<idEntity> * >( &data[ offset ] )->GetEntity();
642 tracePtr = reinterpret_cast<trace_t **>( &args[ i ] );
643 if ( *reinterpret_cast<bool *>( &data[ offset ] ) ) {
644 *tracePtr = reinterpret_cast<trace_t *>( &data[ offset + sizeof( bool ) ] );
646 if ( ( *tracePtr )->c.material != NULL ) {
647 // look up the material name to get the material pointer
648 materialName = reinterpret_cast<const char *>( &data[ offset + sizeof( bool ) + sizeof( trace_t ) ] );
649 ( *tracePtr )->c.material = declManager->FindMaterial( materialName, true );
657 gameLocal.Error( "idEvent::ServiceFastEvents : Invalid arg format '%s' string for '%s' event.", formatspec, ev->GetName() );
661 // the event is removed from its list so that if then object
662 // is deleted, the event won't be freed twice
663 event->eventNode.Remove();
664 assert( event->object );
665 event->object->ProcessEventArgPtr( ev, args );
668 // event functions may never leave return values on the FPU stack
669 // enable this code to check if any event call left values on the FPU stack
670 if ( !sys->FPU_StackIsEmpty() ) {
671 gameLocal.Error( "idEvent::ServiceEvents %d: %s left a value on the FPU stack\n", num, event->eventdef->GetName() );
675 // return the event to the free list
678 // Don't allow ourselves to stay in here too long. An abnormally high number
679 // of events being processed is evidence of an infinite loop of events.
681 if ( num > MAX_EVENTSPERFRAME ) {
682 gameLocal.Error( "Event overflow. Possible infinite loop in script." );
693 void idEvent::Init( void ) {
694 gameLocal.Printf( "Initializing event system\n" );
697 gameLocal.Error( "%s", eventErrorMsg );
700 #ifdef CREATE_EVENT_CODE
701 void CreateEventCallbackHandler();
702 CreateEventCallbackHandler();
703 gameLocal.Error( "Wrote event callback handler" );
707 gameLocal.Printf( "...already initialized\n" );
714 eventDataAllocator.Init();
716 gameLocal.Printf( "...%i event definitions\n", idEventDef::NumEventCommands() );
718 // the event system has started
727 void idEvent::Shutdown( void ) {
728 gameLocal.Printf( "Shutdown event system\n" );
730 if ( !initialized ) {
731 gameLocal.Printf( "...not started\n" );
737 eventDataAllocator.Shutdown();
739 // say it is now shutdown
748 void idEvent::Save( idSaveGame *savefile ) {
756 savefile->WriteInt( EventQueue.Num() );
758 event = EventQueue.Next();
759 while( event != NULL ) {
760 savefile->WriteInt( event->time );
761 savefile->WriteString( event->eventdef->GetName() );
762 savefile->WriteString( event->typeinfo->classname );
763 savefile->WriteObject( event->object );
764 savefile->WriteInt( event->eventdef->GetArgSize() );
765 format = event->eventdef->GetArgFormat();
766 for ( i = 0, size = 0; i < event->eventdef->GetNumArgs(); ++i) {
767 dataPtr = &event->data[ event->eventdef->GetArgOffset( i ) ];
768 switch( format[ i ] ) {
770 savefile->WriteFloat( *reinterpret_cast<float *>( dataPtr ) );
771 size += sizeof( float );
773 case D_EVENT_INTEGER :
774 case D_EVENT_ENTITY :
775 case D_EVENT_ENTITY_NULL :
776 savefile->WriteInt( *reinterpret_cast<int *>( dataPtr ) );
777 size += sizeof( int );
779 case D_EVENT_VECTOR :
780 savefile->WriteVec3( *reinterpret_cast<idVec3 *>( dataPtr ) );
781 size += sizeof( idVec3 );
784 validTrace = *reinterpret_cast<bool *>( dataPtr );
785 savefile->WriteBool( validTrace );
786 size += sizeof( bool );
788 size += sizeof( trace_t );
789 const trace_t &t = *reinterpret_cast<trace_t *>( dataPtr + sizeof( bool ) );
790 SaveTrace( savefile, t );
791 if ( t.c.material ) {
792 size += MAX_STRING_LEN;
793 str = reinterpret_cast<char *>( dataPtr + sizeof( bool ) + sizeof( trace_t ) );
794 savefile->Write( str, MAX_STRING_LEN );
802 assert( size == event->eventdef->GetArgSize() );
803 event = event->eventNode.Next();
807 // Save the Fast EventQueue
808 savefile->WriteInt( FastEventQueue.Num() );
810 event = FastEventQueue.Next();
811 while( event != NULL ) {
812 savefile->WriteInt( event->time );
813 savefile->WriteString( event->eventdef->GetName() );
814 savefile->WriteString( event->typeinfo->classname );
815 savefile->WriteObject( event->object );
816 savefile->WriteInt( event->eventdef->GetArgSize() );
817 savefile->Write( event->data, event->eventdef->GetArgSize() );
819 event = event->eventNode.Next();
829 void idEvent::Restore( idRestoreGame *savefile ) {
831 int num, argsize, i, j, size;
837 savefile->ReadInt( num );
839 for ( i = 0; i < num; i++ ) {
840 if ( FreeEvents.IsListEmpty() ) {
841 gameLocal.Error( "idEvent::Restore : No more free events" );
844 event = FreeEvents.Next();
845 event->eventNode.Remove();
846 event->eventNode.AddToEnd( EventQueue );
848 savefile->ReadInt( event->time );
850 // read the event name
851 savefile->ReadString( name );
852 event->eventdef = idEventDef::FindEvent( name );
853 if ( !event->eventdef ) {
854 savefile->Error( "idEvent::Restore: unknown event '%s'", name.c_str() );
857 // read the classtype
858 savefile->ReadString( name );
859 event->typeinfo = idClass::GetClass( name );
860 if ( !event->typeinfo ) {
861 savefile->Error( "idEvent::Restore: unknown class '%s' on event '%s'", name.c_str(), event->eventdef->GetName() );
864 savefile->ReadObject( event->object );
867 savefile->ReadInt( argsize );
868 if ( argsize != event->eventdef->GetArgSize() ) {
869 savefile->Error( "idEvent::Restore: arg size (%d) doesn't match saved arg size(%d) on event '%s'", event->eventdef->GetArgSize(), argsize, event->eventdef->GetName() );
872 event->data = eventDataAllocator.Alloc( argsize );
873 format = event->eventdef->GetArgFormat();
875 for ( j = 0, size = 0; j < event->eventdef->GetNumArgs(); ++j) {
876 dataPtr = &event->data[ event->eventdef->GetArgOffset( j ) ];
877 switch( format[ j ] ) {
879 savefile->ReadFloat( *reinterpret_cast<float *>( dataPtr ) );
880 size += sizeof( float );
882 case D_EVENT_INTEGER :
883 case D_EVENT_ENTITY :
884 case D_EVENT_ENTITY_NULL :
885 savefile->ReadInt( *reinterpret_cast<int *>( dataPtr ) );
886 size += sizeof( int );
888 case D_EVENT_VECTOR :
889 savefile->ReadVec3( *reinterpret_cast<idVec3 *>( dataPtr ) );
890 size += sizeof( idVec3 );
893 savefile->ReadBool( *reinterpret_cast<bool *>( dataPtr ) );
894 size += sizeof( bool );
895 if ( *reinterpret_cast<bool *>( dataPtr ) ) {
896 size += sizeof( trace_t );
897 trace_t &t = *reinterpret_cast<trace_t *>( dataPtr + sizeof( bool ) );
898 RestoreTrace( savefile, t) ;
899 if ( t.c.material ) {
900 size += MAX_STRING_LEN;
901 str = reinterpret_cast<char *>( dataPtr + sizeof( bool ) + sizeof( trace_t ) );
902 savefile->Read( str, MAX_STRING_LEN );
910 assert( size == event->eventdef->GetArgSize() );
917 // Restore the Fast EventQueue
918 savefile->ReadInt( num );
920 for ( i = 0; i < num; i++ ) {
921 if ( FreeEvents.IsListEmpty() ) {
922 gameLocal.Error( "idEvent::Restore : No more free events" );
925 event = FreeEvents.Next();
926 event->eventNode.Remove();
927 event->eventNode.AddToEnd( FastEventQueue );
929 savefile->ReadInt( event->time );
931 // read the event name
932 savefile->ReadString( name );
933 event->eventdef = idEventDef::FindEvent( name );
934 if ( !event->eventdef ) {
935 savefile->Error( "idEvent::Restore: unknown event '%s'", name.c_str() );
938 // read the classtype
939 savefile->ReadString( name );
940 event->typeinfo = idClass::GetClass( name );
941 if ( !event->typeinfo ) {
942 savefile->Error( "idEvent::Restore: unknown class '%s' on event '%s'", name.c_str(), event->eventdef->GetName() );
945 savefile->ReadObject( event->object );
948 savefile->ReadInt( argsize );
949 if ( argsize != event->eventdef->GetArgSize() ) {
950 savefile->Error( "idEvent::Restore: arg size (%d) doesn't match saved arg size(%d) on event '%s'", event->eventdef->GetArgSize(), argsize, event->eventdef->GetName() );
953 event->data = eventDataAllocator.Alloc( argsize );
954 savefile->Read( event->data, argsize );
966 idRestoreGame has a ReadTrace procedure, but unfortunately idEvent wants the material
967 string name at the of the data structure rather than in the middle
970 void idEvent::RestoreTrace( idRestoreGame *savefile, trace_t &trace ) {
971 savefile->ReadFloat( trace.fraction );
972 savefile->ReadVec3( trace.endpos );
973 savefile->ReadMat3( trace.endAxis );
974 savefile->ReadInt( (int&)trace.c.type );
975 savefile->ReadVec3( trace.c.point );
976 savefile->ReadVec3( trace.c.normal );
977 savefile->ReadFloat( trace.c.dist );
978 savefile->ReadInt( trace.c.contents );
979 savefile->ReadInt( (int&)trace.c.material );
980 savefile->ReadInt( trace.c.contents );
981 savefile->ReadInt( trace.c.modelFeature );
982 savefile->ReadInt( trace.c.trmFeature );
983 savefile->ReadInt( trace.c.id );
990 idSaveGame has a WriteTrace procedure, but unfortunately idEvent wants the material
991 string name at the of the data structure rather than in the middle
994 void idEvent::SaveTrace( idSaveGame *savefile, const trace_t &trace ) {
995 savefile->WriteFloat( trace.fraction );
996 savefile->WriteVec3( trace.endpos );
997 savefile->WriteMat3( trace.endAxis );
998 savefile->WriteInt( trace.c.type );
999 savefile->WriteVec3( trace.c.point );
1000 savefile->WriteVec3( trace.c.normal );
1001 savefile->WriteFloat( trace.c.dist );
1002 savefile->WriteInt( trace.c.contents );
1003 savefile->WriteInt( (int&)trace.c.material );
1004 savefile->WriteInt( trace.c.contents );
1005 savefile->WriteInt( trace.c.modelFeature );
1006 savefile->WriteInt( trace.c.trmFeature );
1007 savefile->WriteInt( trace.c.id );
1012 #ifdef CREATE_EVENT_CODE
1015 CreateEventCallbackHandler
1018 void CreateEventCallbackHandler( void ) {
1022 char argString[ D_EVENT_MAXARGS + 1 ];
1027 file = fileSystem->OpenFileWrite( "Callbacks.cpp" );
1029 file->Printf( "// generated file - see CREATE_EVENT_CODE\n\n" );
1031 for( i = 1; i <= D_EVENT_MAXARGS; i++ ) {
1033 file->Printf( "\t/*******************************************************\n\n\t\t%d args\n\n\t*******************************************************/\n\n", i );
1035 for ( j = 0; j < ( 1 << i ); j++ ) {
1036 for( k = 0; k < i; k++ ) {
1037 argString[ k ] = j & ( 1 << k ) ? 'f' : 'i';
1039 argString[ i ] = '\0';
1044 for( k = 0; k < i; k++ ) {
1045 if ( j & ( 1 << k ) ) {
1046 string1 += "const float";
1047 string2 += va( "*( float * )&data[ %d ]", k );
1049 string1 += "const int";
1050 string2 += va( "data[ %d ]", k );
1059 file->Printf( "\tcase %d :\n\t\ttypedef void ( idClass::*eventCallback_%s_t )( %s );\n", ( 1 << ( i + D_EVENT_MAXARGS ) ) + j, argString, string1.c_str() );
1060 file->Printf( "\t\t( this->*( eventCallback_%s_t )callback )( %s );\n\t\tbreak;\n\n", argString, string2.c_str() );
1065 fileSystem->CloseFile( file );