/* ================= ShutdownGame ================= */ void ShutdownGame( void ) { gi.Printf ("==== ShutdownGame ====\n"); gi.Printf ("... ICARUS_Shutdown\n"); ICARUS_Shutdown (); //Shut ICARUS down gi.Printf ("... Reference Tags Cleared\n"); TAG_Init(); //Clear the reference tags gi.Printf ("... Navigation Data Cleared\n"); NAV_Shutdown(); // write all the client session data so we can get it back G_WriteSessionData(); /* Ghoul2 Insert Start */ gi.Printf ("... Ghoul2 Models Shutdown\n"); for (int i=0; i<MAX_GENTITIES; i++) { gi.G2API_CleanGhoul2Models(g_entities[i].ghoul2); } /* Ghoul2 Insert End */ }
void NAV_CheckCalcPaths( void ) { if ( navCalcPathTime && navCalcPathTime < level.time ) {//first time we've ever loaded this map... //clear all the failed edges navigator.ClearAllFailedEdges(); //Calculate all paths NAV_CalculatePaths( level.mapname, giMapChecksum ); navigator.CalculatePaths(); #ifndef FINAL_BUILD if ( fatalErrors ) { gi.Printf( S_COLOR_RED"Not saving .nav file due to fatal nav errors\n" ); } else #endif if ( navigator.Save( level.mapname, giMapChecksum ) == qfalse ) { gi.Printf("Unable to save navigations data for map \"%s\" (checksum:%d)\n", level.mapname, giMapChecksum ); } navCalcPathTime = 0; } }
extern "C" __declspec( dllexport ) int __cdecl vmMain ( int command, int arg1, int arg2 /*, ..., arg10); (?) no more than 2 seems to ever be used. */ ) { assert( g_realVmMain ); int retVal = g_realVmMain( command, arg1, arg2 ); if( command == 1 && g_inShutdown ) { g_inShutdown = qfalse; g_realDllEntry = 0; g_realGetGameAPI = 0; g_realShutdown = 0; g_realVmMain = 0; if( g_modShutdown ) { g_imports.Printf( "^5Calling mod_jagamex86.dll's Shutdown()\n" ); g_modShutdown(); } if( g_modJagamex86 ) { g_imports.Printf( "^5Unloading mod_jagamex86.dll\n" ); FreeLibrary( g_modJagamex86 ); } g_imports.Printf( "^5Unloading original_jagamex86.dll\n" ); g_exports = 0; assert( FreeLibrary( g_originalJagamex86 ) ); g_originalJagamex86 = 0; } return retVal; }
template< typename FncPtr > bool FindProcAddress( char* procName, char* dllName, FncPtr& out_func ) { if( !( out_func = (FncPtr) GetProcAddress( g_modJagamex86, procName ) ) ) { g_imports.Printf( "^5Warning: No %s in %s! Ignoring it.\n", procName, dllName ); return false; } return true; }
void Com_Printf( const char *msg, ... ) { va_list argptr; char text[1024]; va_start (argptr, msg); vsprintf (text, msg, argptr); va_end (argptr); gi.Printf ("%s", text); }
/* ================ G_FindTeams Chain together all entities with a matching team field. Entity teams are used for item groups and multi-entity mover groups. All but the first will have the FL_TEAMSLAVE flag set and teammaster field set All but the last will have the teamchain field set to the next one ================ */ void G_FindTeams( void ) { gentity_t *e, *e2; int i, j; int c, c2; c = 0; c2 = 0; // for ( i=1, e=g_entities,i ; i < globals.num_entities ; i++,e++ ) for ( i=1 ; i < globals.num_entities ; i++ ) { // if (!e->inuse) // continue; if(!PInUse(i)) continue; e=&g_entities[i]; if (!e->team) continue; if (e->flags & FL_TEAMSLAVE) continue; e->teammaster = e; c++; c2++; // for (j=i+1, e2=e+1 ; j < globals.num_entities ; j++,e2++) for (j=i+1; j < globals.num_entities ; j++) { // if (!e2->inuse) // continue; if(!PInUse(j)) continue; e2=&g_entities[j]; if (!e2->team) continue; if (e2->flags & FL_TEAMSLAVE) continue; if (!strcmp(e->team, e2->team)) { c2++; e2->teamchain = e->teamchain; e->teamchain = e2; e2->teammaster = e; e2->flags |= FL_TEAMSLAVE; // make sure that targets only point at the master if ( e2->targetname ) { e->targetname = e2->targetname; e2->targetname = NULL; } } } } gi.Printf ("%i teams with %i entities\n", c, c2); }
void InitGame( const char *mapname, const char *spawntarget, int checkSum, const char *entities, int levelTime, int randomSeed, int globalTime, SavedGameJustLoaded_e eSavedGameJustLoaded, qboolean qbLoadTransition ) { int i; giMapChecksum = checkSum; g_eSavedGameJustLoaded = eSavedGameJustLoaded; g_qbLoadTransition = qbLoadTransition; gi.Printf ("------- Game Initialization -------\n"); gi.Printf ("gamename: %s\n", GAMEVERSION); gi.Printf ("gamedate: %s\n", __DATE__); srand( randomSeed ); G_InitCvars(); G_InitMemory(); // set some level globals memset( &level, 0, sizeof( level ) ); level.time = levelTime; level.globalTime = globalTime; Q_strncpyz( level.mapname, mapname, sizeof(level.mapname) ); if ( spawntarget != NULL && spawntarget[0] ) { Q_strncpyz( level.spawntarget, spawntarget, sizeof(level.spawntarget) ); } else { level.spawntarget[0] = 0; } G_InitWorldSession(); // initialize all entities for this game memset( g_entities, 0, MAX_GENTITIES * sizeof(g_entities[0]) ); globals.gentities = g_entities; ClearAllInUse(); // initialize all clients for this game level.maxclients = 1; level.clients = (struct gclient_s *) G_Alloc( level.maxclients * sizeof(level.clients[0]) ); // set client fields on player g_entities[0].client = level.clients; // always leave room for the max number of clients, // even if they aren't all used, so numbers inside that // range are NEVER anything but clients globals.num_entities = MAX_CLIENTS; //Set up NPC init data NPC_InitGame(); TIMER_Clear(); // //ICARUS INIT START gi.Printf("------ ICARUS Initialization ------\n"); gi.Printf("ICARUS version : %1.2f\n", ICARUS_VERSION); Interface_Init( &interface_export ); ICARUS_Init(); gi.Printf ("-----------------------------------\n"); //ICARUS INIT END // IT_LoadItemParms (); ClearRegisteredItems(); //FIXME: if this is from a loadgame, it needs to be sure to write this out whenever you do a savegame since the edges and routes are dynamic... navCalculatePaths = ( navigator.Load( mapname, checkSum ) == qfalse ); // parse the key/value pairs and spawn gentities G_SpawnEntitiesFromString( entities ); // general initialization G_FindTeams(); // SaveRegisteredItems(); gi.Printf ("-----------------------------------\n"); //randomize the rand functions byte num_calls = (byte)timeGetTime(); for(i = 0; i < (int)num_calls; i++) { rand(); } if ( navCalculatePaths ) {//not loaded - need to calc paths navCalcPathTime = level.time + START_TIME_NAV_CALC;//make sure all ents are in and linked } else {//loaded //FIXME: if this is from a loadgame, it needs to be sure to write this //out whenever you do a savegame since the edges and routes are dynamic... //OR: always do a navigator.CheckBlockedEdges() on map startup after nav-load/calc-paths navigator.pathsCalculated = qtrue;//just to be safe? Does this get saved out? No... assumed //need to do this, because combatpoint waypoints aren't saved out...? CP_FindCombatPointWaypoints(); navCalcPathTime = 0; if ( g_eSavedGameJustLoaded == eNO ) {//clear all the failed edges unless we just loaded the game (which would include failed edges) navigator.ClearAllFailedEdges(); } } player = &g_entities[0]; //Init dynamic music level.dmState = DM_EXPLORE; level.dmDebounceTime = 0; level.dmBeatTime = 0; level.curAlertID = 1;//0 is default for lastAlertEvent, so... eventClearTime = 0; }
void G_RunFrame( int levelTime ) { int i; gentity_t *ent; int msec; int ents_inuse=0; // someone's gonna be pissed I put this here... #if AI_TIMERS AITime = 0; navTime = 0; #endif// AI_TIMERS level.framenum++; level.previousTime = level.time; level.time = levelTime; msec = level.time - level.previousTime; NAV_CheckCalcPaths(); //ResetTeamCounters(); AI_UpdateGroups(); if ( d_altRoutes->integer ) { navigator.CheckAllFailedEdges(); } navigator.ClearCheckedNodes(); //remember last waypoint, clear current one // for ( i = 0, ent = &g_entities[0]; i < globals.num_entities ; i++, ent++) for ( i = 0; i < globals.num_entities ; i++) { // if ( !ent->inuse ) // continue; if(!PInUse(i)) continue; ent = &g_entities[i]; if ( ent->waypoint != WAYPOINT_NONE && ent->noWaypointTime < level.time ) { ent->lastWaypoint = ent->waypoint; ent->waypoint = WAYPOINT_NONE; } if ( d_altRoutes->integer ) { navigator.CheckFailedNodes( ent ); } } //Look to clear out old events ClearPlayerAlertEvents(); //Run the frame for all entities // for ( i = 0, ent = &g_entities[0]; i < globals.num_entities ; i++, ent++) for ( i = 0; i < globals.num_entities ; i++) { // if ( !ent->inuse ) // continue; if(!PInUse(i)) continue; ents_inuse++; ent = &g_entities[i]; // clear events that are too old if ( level.time - ent->eventTime > EVENT_VALID_MSEC ) { if ( ent->s.event ) { ent->s.event = 0; // &= EV_EVENT_BITS; if ( ent->client ) { ent->client->ps.externalEvent = 0; } } if ( ent->freeAfterEvent ) { // tempEntities or dropped items completely go away after their event G_FreeEntity( ent ); continue; } else if ( ent->unlinkAfterEvent ) { // items that will respawn will hide themselves after their pickup event ent->unlinkAfterEvent = qfalse; gi.unlinkentity( ent ); } } // temporary entities don't think if ( ent->freeAfterEvent ) continue; G_CheckTasksCompleted(ent); G_Roff( ent ); if( !ent->client ) { if ( !(ent->svFlags & SVF_SELF_ANIMATING) ) {//FIXME: make sure this is done only for models with frames? //Or just flag as animating? if ( ent->s.eFlags & EF_ANIM_ONCE ) { ent->s.frame++; } else if ( !(ent->s.eFlags & EF_ANIM_ALLFAST) ) { G_Animate( ent ); } } } G_CheckSpecialPersistentEvents( ent ); if ( ent->s.eType == ET_MISSILE ) { G_RunMissile( ent ); continue; } if ( ent->s.eType == ET_ITEM ) { G_RunItem( ent ); continue; } if ( ent->s.eType == ET_MOVER ) { if ( ent->model && Q_stricmp( "models/test/mikeg/tie_fighter.md3", ent->model ) == 0 ) { TieFighterThink( ent ); } G_RunMover( ent ); continue; } //The player if ( i == 0 ) { // decay batteries if the goggles are active if ( cg.zoomMode == 1 && ent->client->ps.batteryCharge > 0 ) { ent->client->ps.batteryCharge--; } else if ( cg.zoomMode == 3 && ent->client->ps.batteryCharge > 0 ) { ent->client->ps.batteryCharge -= 2; if ( ent->client->ps.batteryCharge < 0 ) { ent->client->ps.batteryCharge = 0; } } G_CheckEndLevelTimers( ent ); //Recalculate the nearest waypoint for the coming NPC updates NAV_FindPlayerWaypoint(); if( ent->taskManager && !stop_icarus ) { ent->taskManager->Update(); } //dead if ( ent->health <= 0 ) { if ( ent->client->ps.groundEntityNum != ENTITYNUM_NONE ) {//on the ground pitch_roll_for_slope( ent, NULL ); } } continue; // players are ucmd driven } G_RunThink( ent ); // be aware that ent may be free after returning from here, at least one func frees them ClearNPCGlobals(); // but these 2 funcs are ok //UpdateTeamCounters( ent ); // to call anyway on a freed ent. } // perform final fixups on the player ent = &g_entities[0]; if ( ent->inuse ) { ClientEndFrame( ent ); } if( g_numEntities->integer ) { gi.Printf( S_COLOR_WHITE"Number of Entities in use : %d\n", ents_inuse ); } //DEBUG STUFF NAV_ShowDebugInfo(); NPC_ShowDebugInfo(); G_DynamicMusicUpdate(); #if AI_TIMERS AITime -= navTime; if ( AITime > 20 ) { gi.Printf( S_COLOR_RED"ERROR: total AI time: %d\n", AITime ); } else if ( AITime > 10 ) { gi.Printf( S_COLOR_YELLOW"WARNING: total AI time: %d\n", AITime ); } else if ( AITime > 2 ) { gi.Printf( S_COLOR_GREEN"total AI time: %d\n", AITime ); } if ( navTime > 20 ) { gi.Printf( S_COLOR_RED"ERROR: total nav time: %d\n", navTime ); } else if ( navTime > 10 ) { gi.Printf( S_COLOR_YELLOW"WARNING: total nav time: %d\n", navTime ); } else if ( navTime > 2 ) { gi.Printf( S_COLOR_GREEN"total nav time: %d\n", navTime ); } #endif// AI_TIMERS #ifndef FINAL_BUILD if ( delayedShutDown != 0 && delayedShutDown < level.time ) { G_Error( "Game Errors. Scroll up the console to read them.\n" ); } #endif #ifdef _DEBUG if(!(level.framenum&0xff)) { ValidateInUseBits(); } #endif }
/** @brief First function called when the DLL is loaded: Server API? **/ extern "C" __declspec( dllexport ) game_export_t* __cdecl GetGameAPI( game_import_t* imports ) { // static global variables are guaranteed to be 0, I heard. Let's assert that. assert( !g_exports ); assert( !g_originalJagamex86 ); assert( !g_modJagamex86 ); assert( !g_inShutdown ); assert( !g_realDllEntry ); assert( !g_realGetGameAPI ); assert( !g_originalJagamex86 ); assert( !g_realShutdown ); assert( !g_realVmMain ); assert( !g_modShutdown ); imports->Printf( "^5Loading original_jagamex86.dll\n" ); g_inShutdown = qfalse; g_originalJagamex86 = LoadLibrary( "original_jagamex86.dll" ); if( !g_originalJagamex86 ) { // imports->Error would be a bad idea because that'd jmp out of the cleanup code for failed dll loading, causing "Sys_GetGameAPI without Sys_UnloadingGame" imports->Printf( "^1Error: Could not load original_jagamex86.dll!\n" ); return 0; } // Get the original functions if( ! (g_realGetGameAPI = (GetGameAPI_t) GetProcAddress( g_originalJagamex86, "GetGameAPI" ) ) ) { imports->Printf( "^1Error: No GetGameAPI in original_jagamex86.dll!\n" ); return 0; } if( ! (g_realDllEntry = (dllEntry_t) GetProcAddress( g_originalJagamex86, "dllEntry" ) ) ) { imports->Printf( "^1Error: No dllEntry in original_jagamex86.dll!\n" ); return 0; } if( ! (g_realVmMain = (vmMain_t) GetProcAddress( g_originalJagamex86, "vmMain" ) ) ) { imports->Printf( "^1Error: No vmMain in original_jagamex86.dll!\n" ); return 0; } // save the imports for later usage g_imports = *imports; // Get the active mod char fs_game[ 256 + 1 ]; // variables can be up to 256 chars - not sure about trailing \0, so + 1 g_imports.Cvar_VariableStringBuffer( "fs_game", fs_game, sizeof( fs_game ) / sizeof( char ) ); if( *fs_game == '\0' ) { fs_game[0] = 'b'; fs_game[1] = 'a'; fs_game[2] = 's'; fs_game[3] = 'e'; fs_game[4] = '\0'; } g_imports.Printf( "fs_game = %s\n", fs_game ); if( strcmp( fs_game, "base" ) ) { char dllName[ MAX_QPATH + 19 ]; // "/mod_jagamex86.dll\0" is 19 chars. sprintf_s( dllName, 256 + 19, "%s/mod_jagamex86.dll", fs_game ); g_modJagamex86 = LoadLibrary( dllName ); if( g_modJagamex86 ) { g_imports.Printf( "^5Found %s - looking for functions.\n", dllName ); GetGameAPI_t modGetGameAPI; vmMain_t modVmMain; dllEntry_t modDllEntry; SetOriginalFunctions_t modSetOriginalFunctions; if( !FindProcAddress( "GetGameAPI", dllName, modGetGameAPI ) || !FindProcAddress( "vmMain", dllName, modVmMain ) || !FindProcAddress( "dllEntry", dllName, modDllEntry ) || !FindProcAddress( "SetOriginalFunctions", dllName, modSetOriginalFunctions ) ) { FreeLibrary( g_modJagamex86 ); g_modJagamex86 = 0; } else { FindProcAddress( "Shutdown", dllName, g_modShutdown ); // optional - not bad if it fails. modSetOriginalFunctions( g_realGetGameAPI, g_realDllEntry, g_realVmMain ); g_realGetGameAPI = modGetGameAPI; g_realDllEntry = modDllEntry; g_realVmMain = modVmMain; } } else { g_imports.Printf( "^5No %s available - forwarding to original_jagamex86.dll.\n", dllName ); } } // call the "real" GetGameAPI g_exports = g_realGetGameAPI( &g_imports ); if( !g_exports ) { // if that failed, clean up and pass on failure g_realGetGameAPI = 0; g_realDllEntry = 0; g_realVmMain = 0; assert( FreeLibrary( g_originalJagamex86 ) ); g_originalJagamex86 = 0; return 0; } // Change Shutdown to our own wrapper which prepares for library freeing g_realShutdown = g_exports->Shutdown; g_exports->Shutdown = ShutdownWrapper; g_imports.Printf( "^5Successfully loaded original_jagamex86.dll\n" ); return g_exports; }