//Anything above this #include will be ignored by the compiler #include "../qcommon/exe_headers.h" // ICARUS Engine Interface File // // This file is the only section of the ICARUS systems that // is not directly portable from engine to engine. // // -- jweier #include "../game/g_public.h" #include "../server/server.h" #include "interface.h" #include "GameInterface.h" #include "Q3_Interface.h" #include "Q3_Registers.h" #define stringIDExpand(str, strEnum) str, strEnum, ENUM2STRING(strEnum) //#define stringIDExpand(str, strEnum) str,strEnum /* stringID_table_t tagsTable [] = { } */ extern float Q_flrand(float min, float max); extern qboolean COM_ParseString( char **data, char **s ); //======================================================================= interface_export_t interface_export; /* ============ Q3_ReadScript Description : Reads in a file and attaches the script directory properly Return type : static int Argument : const char *name Argument : void **buf ============ */ extern int ICARUS_GetScript( const char *name, char **buf ); //g_icarus.cpp static int Q3_ReadScript( const char *name, void **buf ) { return ICARUS_GetScript( va( "%s/%s", Q3_SCRIPT_DIR, name ), (char**)buf ); //get a (hopefully) cached file } /* ============ Q3_CenterPrint Description : Prints a message in the center of the screen Return type : static void Argument : const char *format Argument : ... ============ */ static void Q3_CenterPrint ( const char *format, ... ) { va_list argptr; char text[1024]; va_start (argptr, format); vsprintf (text, format, argptr); va_end (argptr); // FIXME: added '!' so you can print something that's hasn't been precached, '@' searches only for precache text // this is just a TEMPORARY placeholder until objectives are in!!! -- dmv 11/26/01 if ((text[0] == '@') || text[0] == '!') // It's a key { if( text[0] == '!') { SV_SendServerCommand( NULL, "cp \"%s\"", (text+1) ); return; } SV_SendServerCommand( NULL, "cp \"%s\"", text ); } Q3_DebugPrint( WL_VERBOSE, "%s\n", text); // Just a developers note return; } /* ------------------------- void Q3_ClearTaskID( int *taskID ) WARNING: Clearing a taskID will make that task never finish unless you intend to return the same taskID from somewhere else. ------------------------- */ #ifndef _XBOX // We borrow the one in g_ICARUScb.c void Q3_TaskIDClear( int *taskID ) { *taskID = -1; } #endif /* ------------------------- qboolean Q3_TaskIDPending( sharedEntity_t *ent, taskID_t taskType ) ------------------------- */ qboolean Q3_TaskIDPending( sharedEntity_t *ent, taskID_t taskType ) { if ( !gSequencers[ent->s.number] || !gTaskManagers[ent->s.number] ) { return qfalse; } if ( taskType < TID_CHAN_VOICE || taskType >= NUM_TIDS ) { return qfalse; } if ( ent->taskID[taskType] >= 0 )//-1 is none { return qtrue; } return qfalse; } /* ------------------------- void Q3_TaskIDComplete( sharedEntity_t *ent, taskID_t taskType ) ------------------------- */ void Q3_TaskIDComplete( sharedEntity_t *ent, taskID_t taskType ) { if ( taskType < TID_CHAN_VOICE || taskType >= NUM_TIDS ) { return; } if ( gTaskManagers[ent->s.number] && Q3_TaskIDPending( ent, taskType ) ) {//Complete it gTaskManagers[ent->s.number]->Completed( ent->taskID[taskType] ); //See if any other tasks have the name number and clear them so we don't complete more than once int clearTask = ent->taskID[taskType]; for ( int tid = 0; tid < NUM_TIDS; tid++ ) { if ( ent->taskID[tid] == clearTask ) { Q3_TaskIDClear( &ent->taskID[tid] ); } } //clear it - should be cleared in for loop above //Q3_TaskIDClear( &ent->taskID[taskType] ); } //otherwise, wasn't waiting for a task to complete anyway } /* ------------------------- void Q3_SetTaskID( sharedEntity_t *ent, taskID_t taskType, int taskID ) ------------------------- */ void Q3_TaskIDSet( sharedEntity_t *ent, taskID_t taskType, int taskID ) { if ( taskType < TID_CHAN_VOICE || taskType >= NUM_TIDS ) { return; } //Might be stomping an old task, so complete and clear previous task if there was one Q3_TaskIDComplete( ent, taskType ); ent->taskID[taskType] = taskID; } /* ============ Q3_CheckStringCounterIncrement Description : Return type : static float Argument : const char *string ============ */ static float Q3_CheckStringCounterIncrement( const char *string ) { char *numString; float val = 0.0f; if ( string[0] == '+' ) {//We want to increment whatever the value is by whatever follows the + if ( string[1] ) { numString = (char *)&string[1]; val = atof( numString ); } } else if ( string[0] == '-' ) {//we want to decrement if ( string[1] ) { numString = (char *)&string[1]; val = atof( numString ) * -1; } } return val; } /* ============= Q3_GetEntityByName Returns the sequencer of the entity by the given name ============= */ static sharedEntity_t *Q3_GetEntityByName( const char *name ) { sharedEntity_t *ent; entlist_t::iterator ei; char temp[1024]; if ( name == NULL || name[0] == NULL ) return NULL; strncpy( (char *) temp, name, sizeof(temp) ); temp[sizeof(temp)-1] = 0; ei = ICARUS_EntList.find( Q_strupr( (char *) temp ) ); if ( ei == ICARUS_EntList.end() ) return NULL; ent = SV_GentityNum((*ei).second); return ent; // this now returns the ent instead of the sequencer -- dmv 06/27/01 // if (ent == NULL) // return NULL; // return gSequencers[ent->s.number]; } /* ============= Q3_GetTime Get the current game time ============= */ static DWORD Q3_GetTime( void ) { return svs.time; } /* ============= G_AddSexToMunroString Take any string, look for "kyle/" replace with "kyla/" based on "sex" And: Take any string, look for "/mr_" replace with "/ms_" based on "sex" returns qtrue if changed to ms ============= */ /* static qboolean G_AddSexToMunroString ( char *string, qboolean qDoBoth ) { char *start; if VALIDSTRING( string ) { if ( g_sex->string[0] == 'f' ) { start = strstr( string, "kyle/" ); if ( start != NULL ) { strncpy( start, "kyla", 5 ); return qtrue; } else { start = strrchr( string, '/' ); //get the last slash before the wav if (start != NULL) { if (!strncmp( start, "/mr_", 4) ) { if (qDoBoth) { //we want to change mr to ms start[2] = 's'; //change mr to ms return qtrue; } else { //IF qDoBoth return qfalse; //don't want this one } } } //IF found slash } } //IF Female else { //i'm male start = strrchr( string, '/' ); //get the last slash before the wav if (start != NULL) { if (!strncmp( start, "/ms_", 4) ) { return qfalse; //don't want this one } } //IF found slash } } //if VALIDSTRING return qtrue; } */ /* ============= Q3_PlaySound Plays a sound from an entity ============= */ static int Q3_PlaySound( int taskID, int entID, const char *name, const char *channel ) { T_G_ICARUS_PLAYSOUND *sharedMem = (T_G_ICARUS_PLAYSOUND *)sv.mSharedMemory; sharedMem->taskID = taskID; sharedMem->entID = entID; strcpy(sharedMem->name, name); strcpy(sharedMem->channel, channel); return VM_Call(gvm, GAME_ICARUS_PLAYSOUND); } /* ============ Q3_SetVar Description : Return type : static void Argument : int taskID Argument : int entID Argument : const char *type_name Argument : const char *data ============ */ void Q3_SetVar( int taskID, int entID, const char *type_name, const char *data ) { int vret = Q3_VariableDeclared( type_name ) ; float float_data; float val = 0.0f; if ( vret != VTYPE_NONE ) { switch ( vret ) { case VTYPE_FLOAT: //Check to see if increment command if ( (val = Q3_CheckStringCounterIncrement( data )) ) { Q3_GetFloatVariable( type_name, &float_data ); float_data += val; } else { float_data = atof((char *) data); } Q3_SetFloatVariable( type_name, float_data ); break; case VTYPE_STRING: Q3_SetStringVariable( type_name, data ); break; case VTYPE_VECTOR: Q3_SetVectorVariable( type_name, (char *) data ); break; } return; } Q3_DebugPrint( WL_ERROR, "%s variable or field not found!\n", type_name ); } /* ============ Q3_Set Description : Return type : void Argument : int taskID Argument : int entID Argument : const char *type_name Argument : const char *data ============ */ static void Q3_Set( int taskID, int entID, const char *type_name, const char *data ) { T_G_ICARUS_SET *sharedMem = (T_G_ICARUS_SET *)sv.mSharedMemory; sharedMem->taskID = taskID; sharedMem->entID = entID; strcpy(sharedMem->type_name, type_name); strcpy(sharedMem->data, data); if (VM_Call(gvm, GAME_ICARUS_SET)) { gTaskManagers[entID]->Completed( taskID ); } } /* ============ Q3_Evaluate Description : Return type : int Argument : int p1Type Argument : const char *p1 Argument : int p2Type Argument : const char *p2 Argument : int operatorType ============ */ static int Q3_Evaluate( int p1Type, const char *p1, int p2Type, const char *p2, int operatorType ) { float f1=0, f2=0; vec3_t v1, v2; char *c1=0, *c2=0; int i1=0, i2=0; //Always demote to int on float to integer comparisons if ( ( ( p1Type == TK_FLOAT ) && ( p2Type == TK_INT ) ) || ( ( p1Type == TK_INT ) && ( p2Type == TK_FLOAT ) ) ) { p1Type = TK_INT; p2Type = TK_INT; } //Cannot compare two disimilar types if ( p1Type != p2Type ) { Q3_DebugPrint( WL_ERROR, "Q3_Evaluate comparing two disimilar types!\n"); return false; } //Format the parameters switch ( p1Type ) { case TK_FLOAT: sscanf( p1, "%f", &f1 ); sscanf( p2, "%f", &f2 ); break; case TK_INT: sscanf( p1, "%d", &i1 ); sscanf( p2, "%d", &i2 ); break; case TK_VECTOR: sscanf( p1, "%f %f %f", &v1[0], &v1[1], &v1[2] ); sscanf( p2, "%f %f %f", &v2[0], &v2[1], &v2[2] ); break; case TK_STRING: case TK_IDENTIFIER: c1 = (char *) p1; c2 = (char *) p2; break; default: Q3_DebugPrint( WL_WARNING, "Q3_Evaluate unknown type used!\n"); return false; } //Compare them and return the result //FIXME: YUCK!!! Better way to do this? switch ( operatorType ) { // // EQUAL TO // case TK_EQUALS: switch ( p1Type ) { case TK_FLOAT: return (int) ( f1 == f2 ); break; case TK_INT: return (int) ( i1 == i2 ); break; case TK_VECTOR: return (int) VectorCompare( v1, v2 ); break; case TK_STRING: case TK_IDENTIFIER: return (int) !Q_stricmp( c1, c2 ); //NOTENOTE: The script uses proper string comparison logic (ex. ( a == a ) == true ) break; default: Q3_DebugPrint( WL_ERROR, "Q3_Evaluate unknown type used!\n"); return false; } break; // // GREATER THAN // case TK_GREATER_THAN: switch ( p1Type ) { case TK_FLOAT: return (int) ( f1 > f2 ); break; case TK_INT: return (int) ( i1 > i2 ); break; case TK_VECTOR: Q3_DebugPrint( WL_ERROR, "Q3_Evaluate vector comparisons of type GREATER THAN cannot be performed!"); return false; break; case TK_STRING: case TK_IDENTIFIER: Q3_DebugPrint( WL_ERROR, "Q3_Evaluate string comparisons of type GREATER THAN cannot be performed!"); return false; break; default: Q3_DebugPrint( WL_ERROR, "Q3_Evaluate unknown type used!\n"); return false; } break; // // LESS THAN // case TK_LESS_THAN: switch ( p1Type ) { case TK_FLOAT: return (int) ( f1 < f2 ); break; case TK_INT: return (int) ( i1 < i2 ); break; case TK_VECTOR: Q3_DebugPrint( WL_ERROR, "Q3_Evaluate vector comparisons of type LESS THAN cannot be performed!"); return false; break; case TK_STRING: case TK_IDENTIFIER: Q3_DebugPrint( WL_ERROR, "Q3_Evaluate string comparisons of type LESS THAN cannot be performed!"); return false; break; default: Q3_DebugPrint( WL_ERROR, "Q3_Evaluate unknown type used!\n"); return false; } break; // // NOT // case TK_NOT: //NOTENOTE: Implied "NOT EQUAL TO" switch ( p1Type ) { case TK_FLOAT: return (int) ( f1 != f2 ); break; case TK_INT: return (int) ( i1 != i2 ); break; case TK_VECTOR: return (int) !VectorCompare( v1, v2 ); break; case TK_STRING: case TK_IDENTIFIER: return (int) Q_stricmp( c1, c2 ); break; default: Q3_DebugPrint( WL_ERROR, "Q3_Evaluate unknown type used!\n"); return false; } break; default: Q3_DebugPrint( WL_ERROR, "Q3_Evaluate unknown operator used!\n"); break; } return false; } /* ------------------------- Q3_CameraFade ------------------------- */ static void Q3_CameraFade( float sr, float sg, float sb, float sa, float dr, float dg, float db, float da, float duration ) { Q3_DebugPrint( WL_WARNING, "Q3_CameraFade: NOT SUPPORTED IN MP\n"); } /* ------------------------- Q3_CameraPath ------------------------- */ static void Q3_CameraPath( const char *name ) { Q3_DebugPrint( WL_WARNING, "Q3_CameraPath: NOT SUPPORTED IN MP\n"); } /* ------------------------- Q3_DebugPrint ------------------------- */ void Q3_DebugPrint( int level, const char *format, ... ) { //Don't print messages they don't want to see //if ( g_ICARUSDebug->integer < level ) if (!com_developer || !com_developer->integer) return; va_list argptr; char text[1024]; va_start (argptr, format); vsprintf (text, format, argptr); va_end (argptr); //Add the color formatting switch ( level ) { case WL_ERROR: Com_Printf ( S_COLOR_RED"ERROR: %s", text ); break; case WL_WARNING: Com_Printf ( S_COLOR_YELLOW"WARNING: %s", text ); break; case WL_DEBUG: { int entNum; char *buffer; sscanf( text, "%d", &entNum ); if ( ( ICARUS_entFilter >= 0 ) && ( ICARUS_entFilter != entNum ) ) return; buffer = (char *) text; buffer += 5; if ( ( entNum < 0 ) || ( entNum > MAX_GENTITIES ) ) entNum = 0; Com_Printf ( S_COLOR_BLUE"DEBUG: %s(%d): %s\n", SV_GentityNum(entNum)->script_targetname, entNum, buffer ); break; } default: case WL_VERBOSE: Com_Printf ( S_COLOR_GREEN"INFO: %s", text ); break; } } void CGCam_Anything( void ) { Q3_DebugPrint( WL_WARNING, "Camera functions NOT SUPPORTED IN MP\n"); } //These are useless for MP. Just taking it for now since I don't want to remove all calls to this in ICARUS. int AppendToSaveGame(unsigned long chid, void *data, int length) { return 1; } // Changed by BTO (VV) - Visual C++ 7.1 doesn't allow default args on funcion pointers int ReadFromSaveGame(unsigned long chid, void *pvAddress, int iLength /* , void **ppvAddressPtr = NULL */ ) { return 1; } void CGCam_Enable( void ) { CGCam_Anything(); } void CGCam_Disable( void ) { CGCam_Anything(); } void CGCam_Zoom( float FOV, float duration ) { CGCam_Anything(); } void CGCam_Pan( vec3_t dest, vec3_t panDirection, float duration ) { CGCam_Anything(); } void CGCam_Move( vec3_t dest, float duration ) { CGCam_Anything(); } #ifdef _XBOX void CGCam_Shake( float intensity, int duration ); #else void CGCam_Shake( float intensity, int duration ) { CGCam_Anything(); } #endif void CGCam_Follow( const char *cameraGroup, float speed, float initLerp ) { CGCam_Anything(); } void CGCam_Track( const char *trackName, float speed, float initLerp ) { CGCam_Anything(); } void CGCam_Distance( float distance, float initLerp ) { CGCam_Anything(); } void CGCam_Roll( float dest, float duration ) { CGCam_Anything(); } int ICARUS_LinkEntity( int entID, CSequencer *sequencer, CTaskManager *taskManager ); static DWORD Q3_GetTimeScale( void ) { return com_timescale->value; } static void Q3_Lerp2Pos( int taskID, int entID, vec3_t origin, vec3_t angles, float duration ) { T_G_ICARUS_LERP2POS *sharedMem = (T_G_ICARUS_LERP2POS *)sv.mSharedMemory; sharedMem->taskID = taskID; sharedMem->entID = entID; VectorCopy(origin, sharedMem->origin); if (angles) { VectorCopy(angles, sharedMem->angles); sharedMem->nullAngles = qfalse; } else { sharedMem->nullAngles = qtrue; } sharedMem->duration = duration; VM_Call(gvm, GAME_ICARUS_LERP2POS); //We do this in case the values are modified in the game. It would be expected by icarus that //the values passed in here are modified equally. VectorCopy(sharedMem->origin, origin); if (angles) { VectorCopy(sharedMem->angles, angles); } } static void Q3_Lerp2Origin( int taskID, int entID, vec3_t origin, float duration ) { T_G_ICARUS_LERP2ORIGIN *sharedMem = (T_G_ICARUS_LERP2ORIGIN *)sv.mSharedMemory; sharedMem->taskID = taskID; sharedMem->entID = entID; VectorCopy(origin, sharedMem->origin); sharedMem->duration = duration; VM_Call(gvm, GAME_ICARUS_LERP2ORIGIN); VectorCopy(sharedMem->origin, origin); } static void Q3_Lerp2Angles( int taskID, int entID, vec3_t angles, float duration ) { T_G_ICARUS_LERP2ANGLES *sharedMem = (T_G_ICARUS_LERP2ANGLES *)sv.mSharedMemory; sharedMem->taskID = taskID; sharedMem->entID = entID; VectorCopy(angles, sharedMem->angles); sharedMem->duration = duration; VM_Call(gvm, GAME_ICARUS_LERP2ANGLES); VectorCopy(sharedMem->angles, angles); } static int Q3_GetTag( int entID, const char *name, int lookup, vec3_t info ) { int r; T_G_ICARUS_GETTAG *sharedMem = (T_G_ICARUS_GETTAG *)sv.mSharedMemory; sharedMem->entID = entID; strcpy(sharedMem->name, name); sharedMem->lookup = lookup; VectorCopy(info, sharedMem->info); r = VM_Call(gvm, GAME_ICARUS_GETTAG); VectorCopy(sharedMem->info, info); return r; } static void Q3_Lerp2Start( int entID, int taskID, float duration ) { T_G_ICARUS_LERP2START *sharedMem = (T_G_ICARUS_LERP2START *)sv.mSharedMemory; sharedMem->taskID = taskID; sharedMem->entID = entID; sharedMem->duration = duration; VM_Call(gvm, GAME_ICARUS_LERP2START); } static void Q3_Lerp2End( int entID, int taskID, float duration ) { T_G_ICARUS_LERP2END *sharedMem = (T_G_ICARUS_LERP2END *)sv.mSharedMemory; sharedMem->taskID = taskID; sharedMem->entID = entID; sharedMem->duration = duration; VM_Call(gvm, GAME_ICARUS_LERP2END); } static void Q3_Use( int entID, const char *target ) { T_G_ICARUS_USE *sharedMem = (T_G_ICARUS_USE *)sv.mSharedMemory; sharedMem->entID = entID; strcpy(sharedMem->target, target); VM_Call(gvm, GAME_ICARUS_USE); } static void Q3_Kill( int entID, const char *name ) { T_G_ICARUS_KILL *sharedMem = (T_G_ICARUS_KILL *)sv.mSharedMemory; sharedMem->entID = entID; strcpy(sharedMem->name, name); VM_Call(gvm, GAME_ICARUS_KILL); } static void Q3_Remove( int entID, const char *name ) { T_G_ICARUS_REMOVE *sharedMem = (T_G_ICARUS_REMOVE *)sv.mSharedMemory; sharedMem->entID = entID; strcpy(sharedMem->name, name); VM_Call(gvm, GAME_ICARUS_REMOVE); } static void Q3_Play( int taskID, int entID, const char *type, const char *name ) { T_G_ICARUS_PLAY *sharedMem = (T_G_ICARUS_PLAY *)sv.mSharedMemory; sharedMem->taskID = taskID; sharedMem->entID = entID; strcpy(sharedMem->type, type); strcpy(sharedMem->name, name); VM_Call(gvm, GAME_ICARUS_PLAY); } static int Q3_GetFloat( int entID, int type, const char *name, float *value ) { int r; T_G_ICARUS_GETFLOAT *sharedMem = (T_G_ICARUS_GETFLOAT *)sv.mSharedMemory; sharedMem->entID = entID; sharedMem->type = type; strcpy(sharedMem->name, name); sharedMem->value = 0;//*value; r = VM_Call(gvm, GAME_ICARUS_GETFLOAT); *value = sharedMem->value; return r; } static int Q3_GetVector( int entID, int type, const char *name, vec3_t value ) { int r; T_G_ICARUS_GETVECTOR *sharedMem = (T_G_ICARUS_GETVECTOR *)sv.mSharedMemory; sharedMem->entID = entID; sharedMem->type = type; strcpy(sharedMem->name, name); VectorCopy(value, sharedMem->value); r = VM_Call(gvm, GAME_ICARUS_GETVECTOR); VectorCopy(sharedMem->value, value); return r; } static int Q3_GetString( int entID, int type, const char *name, char **value ) { int r; T_G_ICARUS_GETSTRING *sharedMem = (T_G_ICARUS_GETSTRING *)sv.mSharedMemory; sharedMem->entID = entID; sharedMem->type = type; strcpy(sharedMem->name, name); r = VM_Call(gvm, GAME_ICARUS_GETSTRING); //rww - careful with this, next time shared memory is altered this will get stomped *value = &sharedMem->value[0]; return r; } /* ============ Interface_Init Description : Inits the interface for the game Return type : void Argument : interface_export_t *pe ============ */ void Interface_Init( interface_export_t *pe ) { //TODO: This is where you link up all your functions to the engine //General pe->I_LoadFile = Q3_ReadScript; pe->I_CenterPrint = Q3_CenterPrint; pe->I_DPrintf = Q3_DebugPrint; pe->I_GetEntityByName = Q3_GetEntityByName; pe->I_GetTime = Q3_GetTime; pe->I_GetTimeScale = Q3_GetTimeScale; pe->I_PlaySound = Q3_PlaySound; pe->I_Lerp2Pos = Q3_Lerp2Pos; pe->I_Lerp2Origin = Q3_Lerp2Origin; pe->I_Lerp2Angles = Q3_Lerp2Angles; pe->I_GetTag = Q3_GetTag; pe->I_Lerp2Start = Q3_Lerp2Start; pe->I_Lerp2End = Q3_Lerp2End; pe->I_Use = Q3_Use; pe->I_Kill = Q3_Kill; pe->I_Remove = Q3_Remove; pe->I_Set = Q3_Set; pe->I_Random = Q_flrand; pe->I_Play = Q3_Play; //Camera functions pe->I_CameraEnable = CGCam_Enable; pe->I_CameraDisable = CGCam_Disable; pe->I_CameraZoom = CGCam_Zoom; pe->I_CameraMove = CGCam_Move; pe->I_CameraPan = CGCam_Pan; pe->I_CameraRoll = CGCam_Roll; pe->I_CameraTrack = CGCam_Track; pe->I_CameraFollow = CGCam_Follow; pe->I_CameraDistance = CGCam_Distance; pe->I_CameraShake = CGCam_Shake; pe->I_CameraFade = Q3_CameraFade; pe->I_CameraPath = Q3_CameraPath; //Variable information pe->I_GetFloat = Q3_GetFloat; pe->I_GetVector = Q3_GetVector; pe->I_GetString = Q3_GetString; pe->I_Evaluate = Q3_Evaluate; pe->I_DeclareVariable = Q3_DeclareVariable; pe->I_FreeVariable = Q3_FreeVariable; //Save / Load functions pe->I_WriteSaveData = AppendToSaveGame; pe->I_ReadSaveData = ReadFromSaveGame; pe->I_LinkEntity = ICARUS_LinkEntity; }