qboolean G_ActivateBehavior (gentity_t *self, int bset ) { bState_t bSID = (bState_t)-1; char *bs_name = NULL; if ( !self ) { return qfalse; } bs_name = self->behaviorSet[bset]; if( !(VALIDSTRING( bs_name )) ) { return qfalse; } if ( self->NPC ) { bSID = (bState_t)(GetIDForString( BSTable, bs_name )); } if(bSID > -1) { self->NPC->tempBehavior = BS_DEFAULT; self->NPC->behaviorState = bSID; if ( bSID == BS_SEARCH || bSID == BS_WANDER ) { //FIXME: Reimplement? if( self->waypoint != WAYPOINT_NONE ) { NPC_BSSearchStart( self->waypoint, bSID ); } else { self->waypoint = NAV::GetNearestNode(self); if( self->waypoint != WAYPOINT_NONE ) { NPC_BSSearchStart( self->waypoint, bSID ); } } } } else { Quake3Game()->DebugPrint( IGameInterface::WL_VERBOSE, "%s attempting to run bSet %s (%s)\n", self->targetname, GetStringForID( BSETTable, bset ), bs_name ); Quake3Game()->RunScript( self, bs_name ); } return qtrue; }
void WriteLevel(qboolean qbAutosave) { if (!qbAutosave) //-always save the client { // write out one client - us! // assert(level.maxclients == 1); // I'll need to know if this changes, otherwise I'll need to change the way ReadGame works gclient_t client = level.clients[0]; EnumerateFields(savefields_gClient, (byte *)&client, 'GCLI', sizeof(client)); WriteLevelLocals(); // level_locals_t level } OBJ_SaveObjectiveData(); FX_Write(); ///////////// WriteGEntities(qbAutosave); Quake3Game()->VariableSave(); G_LoadSave_WriteMiscData(); extern void CG_WriteTheEvilCGHackStuff(void); CG_WriteTheEvilCGHackStuff(); // (Do NOT put any write-code below this line) // // put out an end-marker so that the load code can check everything was read in... // static int iDONE = 1234; gi.AppendToSaveGame('DONE', &iDONE, sizeof(iDONE)); }
void target_counter_use( gentity_t *self, gentity_t *other, gentity_t *activator ) { if ( self->count == 0 ) { return; } //gi.Printf("target_counter %s used by %s, entnum %d\n", self->targetname, activator->targetname, activator->s.number ); self->count--; if ( activator ) { Quake3Game()->DebugPrint( IGameInterface::WL_VERBOSE, "target_counter %s used by %s (%d/%d)\n", self->targetname, activator->targetname, (self->max_health-self->count), self->max_health ); } if ( self->count ) { if ( self->target2 ) { //gi.Printf("target_counter %s firing target2 from %s, entnum %d\n", self->targetname, activator->targetname, activator->s.number ); G_UseTargets2( self, activator, self->target2 ); } return; } G_ActivateBehavior( self,BSET_USE ); if ( self->spawnflags & 128 ) { self->svFlags |= SVF_INACTIVE; } self->activator = activator; G_UseTargets( self, activator ); if ( self->count == 0 ) { if ( self->bounceCount == 0 ) { return; } self->count = self->max_health; if ( self->bounceCount > 0 ) {//-1 means bounce back forever self->bounceCount--; } } }
void WriteLevel(qboolean qbAutosave) { if (!qbAutosave) //-always save the client { // write out one client - us! // assert(level.maxclients == 1); // I'll need to know if this changes, otherwise I'll need to change the way ReadGame works gclient_t client = level.clients[0]; EnumerateFields(savefields_gClient, &client, INT_ID('G','C','L','I')); WriteLevelLocals(); // level_locals_t level } OBJ_SaveObjectiveData(); FX_Write(); ///////////// WriteGEntities(qbAutosave); Quake3Game()->VariableSave(); G_LoadSave_WriteMiscData(); extern void CG_WriteTheEvilCGHackStuff(void); CG_WriteTheEvilCGHackStuff(); // (Do NOT put any write-code below this line) // // put out an end-marker so that the load code can check everything was read in... // static int iDONE = 1234; ojk::SavedGameHelper saved_game( ::gi.saved_game); saved_game.write_chunk<int32_t>( INT_ID('D', 'O', 'N', 'E'), iDONE); }
/* ================= ConsoleCommand // these are added in cg_main, CG_Init so they tab-complete ================= */ qboolean ConsoleCommand( void ) { char *cmd; cmd = gi.argv(0); if ( Q_stricmp (cmd, "entitylist") == 0 ) { Svcmd_EntityList_f(); return qtrue; } if (Q_stricmp (cmd, "game_memory") == 0) { Svcmd_GameMem_f(); return qtrue; } // if (Q_stricmp (cmd, "addbot") == 0) { // Svcmd_AddBot_f(); // return qtrue; // } if (Q_stricmp (cmd, "nav") == 0) { if ( !g_cheats->integer ) { gi.SendServerCommand( 0, "print \"Cheats are not enabled on this server.\n\""); return qfalse; } Svcmd_Nav_f (); return qtrue; } if (Q_stricmp (cmd, "npc") == 0) { if ( !g_cheats->integer ) { gi.SendServerCommand( 0, "print \"Cheats are not enabled on this server.\n\""); return qfalse; } Svcmd_NPC_f (); return qtrue; } if (Q_stricmp (cmd, "use") == 0) { if ( !g_cheats->integer ) { gi.SendServerCommand( 0, "print \"Cheats are not enabled on this server.\n\""); return qfalse; } Svcmd_Use_f (); return qtrue; } if ( Q_stricmp( cmd, "ICARUS" ) == 0 ) { if ( !g_cheats->integer ) { gi.SendServerCommand( 0, "print \"Cheats are not enabled on this server.\n\""); return qfalse; } Quake3Game()->Svcmd(); return qtrue; } if ( Q_stricmp( cmd, "saberColor" ) == 0 ) { if ( !g_cheats->integer ) { gi.SendServerCommand( 0, "print \"Cheats are not enabled on this server.\n\""); return qfalse; } Svcmd_SaberColor_f(); return qtrue; } if ( Q_stricmp( cmd, "saber" ) == 0 ) { if ( !g_cheats->integer ) { gi.SendServerCommand( 0, "print \"Cheats are not enabled on this server.\n\""); return qfalse; } Svcmd_Saber_f(); return qtrue; } if ( Q_stricmp( cmd, "saberblade" ) == 0 ) { if ( !g_cheats->integer ) { gi.SendServerCommand( 0, "print \"Cheats are not enabled on this server.\n\""); return qfalse; } Svcmd_SaberBlade_f(); return qtrue; } if ( Q_stricmp( cmd, "setForceJump" ) == 0 ) { Svcmd_ForceJump_f(); return qtrue; } if ( Q_stricmp( cmd, "setSaberThrow" ) == 0 ) { Svcmd_SaberThrow_f(); return qtrue; } if ( Q_stricmp( cmd, "setForceHeal" ) == 0 ) { Svcmd_ForceHeal_f(); return qtrue; } if ( Q_stricmp( cmd, "setForcePush" ) == 0 ) { Svcmd_ForcePush_f(); return qtrue; } if ( Q_stricmp( cmd, "setForcePull" ) == 0 ) { Svcmd_ForcePull_f(); return qtrue; } if ( Q_stricmp( cmd, "setForceSpeed" ) == 0 ) { Svcmd_ForceSpeed_f(); return qtrue; } if ( Q_stricmp( cmd, "setForceGrip" ) == 0 ) { Svcmd_ForceGrip_f(); return qtrue; } if ( Q_stricmp( cmd, "setForceLightning" ) == 0 ) { Svcmd_ForceLightning_f(); return qtrue; } if ( Q_stricmp( cmd, "setMindTrick" ) == 0 ) { Svcmd_MindTrick_f(); return qtrue; } if ( Q_stricmp( cmd, "setSaberDefense" ) == 0 ) { Svcmd_SaberDefense_f(); return qtrue; } if ( Q_stricmp( cmd, "setSaberOffense" ) == 0 ) { Svcmd_SaberOffense_f(); return qtrue; } if ( Q_stricmp( cmd, "setForceRage" ) == 0 ) { Svcmd_ForceSetLevel_f( FP_RAGE ); return qtrue; } if ( Q_stricmp( cmd, "setForceDrain" ) == 0 ) { Svcmd_ForceSetLevel_f( FP_DRAIN ); return qtrue; } if ( Q_stricmp( cmd, "setForceProtect" ) == 0 ) { Svcmd_ForceSetLevel_f( FP_PROTECT ); return qtrue; } if ( Q_stricmp( cmd, "setForceAbsorb" ) == 0 ) { Svcmd_ForceSetLevel_f( FP_ABSORB ); return qtrue; } if ( Q_stricmp( cmd, "setForceSight" ) == 0 ) { Svcmd_ForceSetLevel_f( FP_SEE ); return qtrue; } if ( Q_stricmp( cmd, "setForceAll" ) == 0 ) { Svcmd_ForceJump_f(); Svcmd_SaberThrow_f(); Svcmd_ForceHeal_f(); Svcmd_ForcePush_f(); Svcmd_ForcePull_f(); Svcmd_ForceSpeed_f(); Svcmd_ForceGrip_f(); Svcmd_ForceLightning_f(); Svcmd_MindTrick_f(); Svcmd_SaberDefense_f(); Svcmd_SaberOffense_f(); Svcmd_ForceSetLevel_f( FP_RAGE ); Svcmd_ForceSetLevel_f( FP_DRAIN ); Svcmd_ForceSetLevel_f( FP_PROTECT ); Svcmd_ForceSetLevel_f( FP_ABSORB ); Svcmd_ForceSetLevel_f( FP_SEE ); for ( int i = SS_NONE+1; i < SS_NUM_SABER_STYLES; i++ ) { g_entities[0].client->ps.saberStylesKnown |= (1<<i); } return qtrue; } if ( Q_stricmp( cmd, "saberAttackCycle" ) == 0 ) { Svcmd_SaberAttackCycle_f(); return qtrue; } if ( Q_stricmp( cmd, "runscript" ) == 0 ) { if ( !g_cheats->integer ) { gi.SendServerCommand( 0, "print \"Cheats are not enabled on this server.\n\""); return qfalse; } char *cmd2 = gi.argv(1); if ( cmd2 && cmd2[0] ) { char *cmd3 = gi.argv(2); if ( cmd3 && cmd3[0] ) { gentity_t *found = NULL; if ( (found = G_Find(NULL, FOFS(targetname), cmd2 ) ) != NULL ) { Quake3Game()->RunScript( found, cmd3 ); } else { //can't find cmd2 gi.Printf( S_COLOR_RED"runscript: can't find targetname %s\n", cmd2 ); } } else { Quake3Game()->RunScript( &g_entities[0], cmd2 ); } } else { gi.Printf( S_COLOR_RED"usage: runscript <ent targetname> scriptname\n" ); } //FIXME: else warning return qtrue; } if ( Q_stricmp( cmd, "playerteam" ) == 0 ) { if ( !g_cheats->integer ) { gi.SendServerCommand( 0, "print \"Cheats are not enabled on this server.\n\""); return qfalse; } char *cmd2 = gi.argv(1); int n; if ( !*cmd2 || !cmd2[0] ) { gi.Printf( S_COLOR_RED"'playerteam' - change player team, requires a team name!\n" ); gi.Printf( S_COLOR_RED"Valid team names are:\n"); for ( n = (TEAM_FREE + 1); n < TEAM_NUM_TEAMS; n++ ) { gi.Printf( S_COLOR_RED"%s\n", GetStringForID( TeamTable, n ) ); } } else { team_t team; team = (team_t)GetIDForString( TeamTable, cmd2 ); if ( team == -1 ) { gi.Printf( S_COLOR_RED"'playerteam' unrecognized team name %s!\n", cmd2 ); gi.Printf( S_COLOR_RED"Valid team names are:\n"); for ( n = TEAM_FREE; n < TEAM_NUM_TEAMS; n++ ) { gi.Printf( S_COLOR_RED"%s\n", GetStringForID( TeamTable, n ) ); } } else { g_entities[0].client->playerTeam = team; //FIXME: convert Imperial, Malon, Hirogen and Klingon to Scavenger? } } return qtrue; } if ( Q_stricmp( cmd, "control" ) == 0 ) { if ( !g_cheats->integer ) { gi.SendServerCommand( 0, "print \"Cheats are not enabled on this server.\n\""); return qfalse; } char *cmd2 = gi.argv(1); if ( !*cmd2 || !cmd2[0] ) { if ( !G_ClearViewEntity( &g_entities[0] ) ) { gi.Printf( S_COLOR_RED"control <NPC_targetname>\n", cmd2 ); } } else { Q3_SetViewEntity( 0, cmd2 ); } return qtrue; } if ( Q_stricmp( cmd, "grab" ) == 0 ) { if ( !g_cheats->integer ) { gi.SendServerCommand( 0, "print \"Cheats are not enabled on this server.\n\""); return qfalse; } char *cmd2 = gi.argv(1); if ( !*cmd2 || !cmd2[0] ) { if ( !G_ReleaseEntity( &g_entities[0] ) ) { gi.Printf( S_COLOR_RED"grab <NPC_targetname>\n", cmd2 ); } } else { G_GrabEntity( &g_entities[0], cmd2 ); } return qtrue; } if ( Q_stricmp( cmd, "knockdown" ) == 0 ) { if ( !g_cheats->integer ) { gi.SendServerCommand( 0, "print \"Cheats are not enabled on this server.\n\""); return qfalse; } G_Knockdown( &g_entities[0], &g_entities[0], vec3_origin, 300, qtrue ); return qtrue; } if ( Q_stricmp( cmd, "playerModel" ) == 0 ) { if ( gi.argc() == 1 ) { gi.Printf( S_COLOR_RED"USAGE: playerModel <NPC Name>\n playerModel <g2model> <skinhead> <skintorso> <skinlower>\n playerModel player (builds player from customized menu settings)\n" ); gi.Printf( "playerModel = %s ", va("%s %s %s %s\n", g_char_model->string, g_char_skin_head->string, g_char_skin_torso->string, g_char_skin_legs->string ) ); } else if ( gi.argc() == 2 ) { G_ChangePlayerModel( &g_entities[0], gi.argv(1) ); } else if ( gi.argc() == 5 ) { //instead of setting it directly via a command, we now store it in cvars //G_ChangePlayerModel( &g_entities[0], va("%s|%s|%s|%s", gi.argv(1), gi.argv(2), gi.argv(3), gi.argv(4)) ); gi.cvar_set("g_char_model", gi.argv(1) ); gi.cvar_set("g_char_skin_head", gi.argv(2) ); gi.cvar_set("g_char_skin_torso", gi.argv(3) ); gi.cvar_set("g_char_skin_legs", gi.argv(4) ); G_InitPlayerFromCvars( &g_entities[0] ); } return qtrue; } if ( Q_stricmp( cmd, "playerTint" ) == 0 ) { if ( gi.argc() == 4 ) { g_entities[0].client->renderInfo.customRGBA[0] = atoi(gi.argv(1)); g_entities[0].client->renderInfo.customRGBA[1] = atoi(gi.argv(2)); g_entities[0].client->renderInfo.customRGBA[2] = atoi(gi.argv(3)); gi.cvar_set("g_char_color_red", gi.argv(1) ); gi.cvar_set("g_char_color_green", gi.argv(2) ); gi.cvar_set("g_char_color_blue", gi.argv(3) ); } else { gi.Printf( S_COLOR_RED"USAGE: playerTint <red 0 - 255> <green 0 - 255> <blue 0 - 255>\n" ); gi.Printf( "playerTint = %s\n", va("%d %d %d", g_char_color_red->integer, g_char_color_green->integer, g_char_color_blue->integer ) ); } return qtrue; } if ( Q_stricmp( cmd, "nexttestaxes" ) == 0 ) { G_NextTestAxes(); } if ( Q_stricmp( cmd, "exitview" ) == 0 ) { Svcmd_ExitView_f(); } if (Q_stricmp (cmd, "iknowkungfu") == 0) { gi.cvar_set( "g_debugMelee", "1" ); G_SetWeapon( &g_entities[0], WP_MELEE ); for ( int i = FP_FIRST; i < NUM_FORCE_POWERS; i++ ) { g_entities[0].client->ps.forcePowersKnown |= ( 1 << i ); if ( i == FP_TELEPATHY ) { g_entities[0].client->ps.forcePowerLevel[i] = FORCE_LEVEL_4; } else { g_entities[0].client->ps.forcePowerLevel[i] = FORCE_LEVEL_3; } } } return qfalse; }
void scriptrunner_run (gentity_t *self) { /* if (self->behaviorSet[BSET_USE]) { char newname[MAX_FILENAME_LENGTH]; sprintf((char *) &newname, "%s/%s", Q3_SCRIPT_DIR, self->behaviorSet[BSET_USE] ); ICARUS_RunScript( self, newname ); } */ if ( self->count != -1 ) { if ( self->count <= 0 ) { self->e_UseFunc = useF_NULL; self->behaviorSet[BSET_USE] = NULL; return; } else { --self->count; } } if (self->behaviorSet[BSET_USE]) { if ( self->spawnflags & 1 ) { if ( !self->activator ) { Quake3Game()->DebugPrint( IGameInterface::WL_ERROR, "target_scriptrunner tried to run on invalid entity!\n"); return; } if ( self->activator->m_iIcarusID == IIcarusInterface::ICARUS_INVALID ) {//Need to be initialized through ICARUS if ( !self->activator->script_targetname || !self->activator->script_targetname[0] ) { //We don't have a script_targetname, so create a new one self->activator->script_targetname = va( "newICARUSEnt%d", numNewICARUSEnts++ ); } if ( Quake3Game()->ValidEntity( self->activator ) ) { Quake3Game()->InitEntity( self->activator ); } else { Quake3Game()->DebugPrint( IGameInterface::WL_ERROR, "target_scriptrunner tried to run on invalid ICARUS activator!\n"); return; } } Quake3Game()->DebugPrint( IGameInterface::WL_VERBOSE, "target_scriptrunner running %s on activator %s\n", self->behaviorSet[BSET_USE], self->activator->targetname ); Quake3Game()->RunScript( self->activator, self->behaviorSet[BSET_USE] ); } else { if ( self->activator ) { Quake3Game()->DebugPrint( IGameInterface::WL_VERBOSE, "target_scriptrunner %s used by %s\n", self->targetname, self->activator->targetname ); } G_ActivateBehavior( self, BSET_USE ); } } if ( self->wait ) { self->nextthink = level.time + self->wait; } }
/* ================= G_FreeEntity Marks the entity as free ================= */ void G_FreeEntity( gentity_t *ed ) { gi.unlinkentity (ed); // unlink from world // Free the Game Element (the entity) and delete the Icarus ID. Quake3Game()->FreeEntity( ed ); /*if ( ed->neverFree ) { return; }*/ if (ed->wayedge!=0) { NAV::WayEdgesNowClear(ed); } // remove any ghoul2 models here gi.G2API_CleanGhoul2Models(ed->ghoul2); if (ed->client && ed->client->NPC_class == CLASS_VEHICLE) { Vehicle_Remove(ed); if ( ed->m_pVehicle ) { gi.Free( ed->m_pVehicle ); } //CVehicleNPC *pVeh = static_cast< CVehicleNPC * >( ed->NPC ); //delete pVeh; //gi.Free((char*)ed->NPC-4);//crazy hack for class vtables } //free this stuff now, rather than waiting until the level ends. if (ed->NPC) { gi.Free(ed->NPC); if(ed->client->clientInfo.customBasicSoundDir && gi.bIsFromZone(ed->client->clientInfo.customBasicSoundDir, TAG_G_ALLOC)) { gi.Free(ed->client->clientInfo.customBasicSoundDir); } if(ed->client->clientInfo.customCombatSoundDir) { #ifdef _MSC_VER assert(*(unsigned int*)ed->client->clientInfo.customCombatSoundDir != 0xfeeefeee); #endif gi.Free(ed->client->clientInfo.customCombatSoundDir); } if(ed->client->clientInfo.customExtraSoundDir) { #ifdef _MSC_VER assert(*(unsigned int*)ed->client->clientInfo.customExtraSoundDir != 0xfeeefeee); #endif gi.Free(ed->client->clientInfo.customExtraSoundDir); } if(ed->client->clientInfo.customJediSoundDir) { gi.Free(ed->client->clientInfo.customJediSoundDir); } if(ed->client->ps.saber[0].name && gi.bIsFromZone(ed->client->ps.saber[0].name, TAG_G_ALLOC) ) { gi.Free(ed->client->ps.saber[0].name); } if(ed->client->ps.saber[0].model && gi.bIsFromZone(ed->client->ps.saber[0].model, TAG_G_ALLOC) ) { gi.Free(ed->client->ps.saber[0].model); } if(ed->client->ps.saber[1].name && gi.bIsFromZone(ed->client->ps.saber[1].name, TAG_G_ALLOC) ) { gi.Free(ed->client->ps.saber[1].name); } if(ed->client->ps.saber[1].model && gi.bIsFromZone(ed->client->ps.saber[1].model, TAG_G_ALLOC) ) { gi.Free(ed->client->ps.saber[1].model); } gi.Free(ed->client); } if (ed->soundSet && gi.bIsFromZone(ed->soundSet, TAG_G_ALLOC)) { gi.Free(ed->soundSet); } if (ed->targetname && gi.bIsFromZone(ed->targetname, TAG_G_ALLOC)) { gi.Free(ed->targetname); } if (ed->NPC_targetname && gi.bIsFromZone(ed->NPC_targetname, TAG_G_ALLOC)) { gi.Free(ed->NPC_targetname); } if (ed->NPC_type && gi.bIsFromZone(ed->NPC_type, TAG_G_ALLOC)) { gi.Free(ed->NPC_type); } if (ed->classname && gi.bIsFromZone(ed->classname, TAG_G_ALLOC)) { gi.Free(ed->classname ); } if (ed->message && gi.bIsFromZone(ed->message, TAG_G_ALLOC)) { gi.Free(ed->message); } if (ed->model && gi.bIsFromZone(ed->model, TAG_G_ALLOC)) { gi.Free(ed->model); } //scripting if (ed->script_targetname && gi.bIsFromZone(ed->script_targetname, TAG_G_ALLOC)) { gi.Free(ed->script_targetname); } if (ed->cameraGroup && gi.bIsFromZone(ed->cameraGroup, TAG_G_ALLOC)) { gi.Free(ed->cameraGroup); } if (ed->paintarget && gi.bIsFromZone(ed->paintarget, TAG_G_ALLOC)) { gi.Free(ed->paintarget); } if(ed->parms) { gi.Free(ed->parms); } //Limbs if (ed->target && gi.bIsFromZone(ed->target , TAG_G_ALLOC)) { gi.Free(ed->target); } if (ed->target2 && gi.bIsFromZone(ed->target2 , TAG_G_ALLOC)) { gi.Free(ed->target2); } if (ed->target3 && gi.bIsFromZone(ed->target3 , TAG_G_ALLOC)) { gi.Free(ed->target3); } if (ed->target4 && gi.bIsFromZone(ed->target4 , TAG_G_ALLOC)) { gi.Free(ed->target4); } if (ed->opentarget) { gi.Free(ed->opentarget); } if (ed->closetarget) { gi.Free(ed->closetarget); } // Free any associated timers TIMER_Clear(ed->s.number); memset (ed, 0, sizeof(*ed)); ed->s.number = ENTITYNUM_NONE; ed->classname = "freed"; ed->freetime = level.time; ed->inuse = qfalse; ClearInUse(ed); }
static void ReadGEntities(qboolean qbAutosave) { int iCount; gi.ReadFromSaveGame('NMED', (void *)&iCount, sizeof(iCount)); int iPreviousEntRead = -1; int i; for (i=0; i<iCount; i++) { int iEntIndex; gi.ReadFromSaveGame('EDNM', (void *)&iEntIndex, sizeof(iEntIndex)); if (iEntIndex >= globals.num_entities) { globals.num_entities = iEntIndex + 1; } if (iPreviousEntRead != iEntIndex-1) { for (int j=iPreviousEntRead+1; j!=iEntIndex; j++) { if ( g_entities[j].inuse ) // not actually necessary { G_FreeEntity(&g_entities[j]); } } } iPreviousEntRead = iEntIndex; // slightly naff syntax here, but makes a few ops clearer later... // gentity_t entity; gentity_t* pEntOriginal = &entity; gentity_t* pEnt = &g_entities[iEntIndex]; *pEntOriginal = *pEnt; // struct copy, so we can refer to original pEntOriginal->ghoul2.kill(); gi.unlinkentity(pEnt); Quake3Game()->FreeEntity( pEnt ); // // sneaky: destroy the ghoul2 object within this struct before binary-loading over the top of it... // gi.G2API_LoadSaveCodeDestructGhoul2Info(pEnt->ghoul2); pEnt->ghoul2.kill(); EvaluateFields(savefields_gEntity, (byte *)pEnt, (byte *)pEntOriginal, 'GENT', sizeof(*pEnt),qfalse); pEnt->ghoul2.kill(); // now for any fiddly bits... // if (pEnt->NPC) // will be qtrue/qfalse { gNPC_t tempNPC; EvaluateFields(savefields_gNPC, (byte *)&tempNPC,(byte *)pEntOriginal->NPC, 'GNPC', sizeof (*pEnt->NPC),qfalse); // so can we pinch the original's one or do we have to alloc a new one?... // if (pEntOriginal->NPC) { // pinch this G_Alloc handle... // pEnt->NPC = pEntOriginal->NPC; } else { // original didn't have one (hmmm...), so make a new one... // //assert(0); // I want to know about this, though not in release pEnt->NPC = (gNPC_t *) G_Alloc(sizeof(*pEnt->NPC)); } // copy over the one we've just loaded... // *pEnt->NPC = tempNPC; // struct copy //FIXME: do we need to do these too? /* if ( pEnt->s.number ) {//not player G_LoadAnimFileSet( *pEnt, *pEnt->NPC_type ); G_SetSkin( *pEnt, *pEnt->NPC_type, NULL );// it probably wasn't the default skin, do we need this at all? } */ } if (pEnt->client == (gclient_t*) -2) // one of Mike G's NPC clients? { gclient_t tempGClient; EvaluateFields(savefields_gClient, (byte *)&tempGClient, (byte *)pEntOriginal->client, 'GCLI', sizeof(*pEnt->client),qtrue);//qfalse); // can we pinch the original's client handle or do we have to alloc a new one?... // if (pEntOriginal->client) { // pinch this G_Alloc handle... // pEnt->client = pEntOriginal->client; } else { // original didn't have one (hmmm...) so make a new one... // pEnt->client = (gclient_t *) G_Alloc(sizeof(*pEnt->client)); } // copy over the one we've just loaded.... // *pEnt->client = tempGClient; // struct copy if ( pEnt->s.number ) {//not player G_ReloadSaberData( pEnt ); } } // Some Icarus thing... (probably) // if (pEnt->parms) // will be qtrue/qfalse { parms_t tempParms; gi.ReadFromSaveGame('PARM', &tempParms, sizeof(tempParms)); // so can we pinch the original's one or do we have to alloc a new one?... // if (pEntOriginal->parms) { // pinch this G_Alloc handle... // pEnt->parms = pEntOriginal->parms; } else { // original didn't have one, so make a new one... // pEnt->parms = (parms_t *) G_Alloc(sizeof(*pEnt->parms)); } // copy over the one we've just loaded... // *pEnt->parms = tempParms; // struct copy } if (pEnt->m_pVehicle) // will be qtrue/qfalse { Vehicle_t tempVehicle; EvaluateFields(savefields_gVHIC, (byte *)&tempVehicle,(byte *)pEntOriginal->m_pVehicle, 'VHIC', sizeof (*pEnt->m_pVehicle),qfalse); // so can we pinch the original's one or do we have to alloc a new one?... // if (pEntOriginal->m_pVehicle) { // pinch this G_Alloc handle... // pEnt->m_pVehicle = pEntOriginal->m_pVehicle; } else { // original didn't have one, so make a new one... // pEnt->m_pVehicle = (Vehicle_t *) gi.Malloc( sizeof(Vehicle_t), TAG_G_ALLOC, qfalse ); } // copy over the one we've just loaded... // *pEnt->m_pVehicle = tempVehicle; // struct copy } // the scary ghoul2 stuff... (fingers crossed) // { char *pGhoul2Data = NULL; gi.ReadFromSaveGame('GHL2', 0, 0, (void**)&pGhoul2Data); gi.G2API_LoadGhoul2Models(pEnt->ghoul2, pGhoul2Data); // if it's going to crash anywhere... <g> gi.Free(pGhoul2Data); } // gi.unlinkentity (pEntOriginal); // ICARUS_FreeEnt( pEntOriginal ); // *pEntOriginal = *pEnt; // struct copy // qboolean qbLinked = pEntOriginal->linked; // pEntOriginal->linked = qfalse; // if (qbLinked) // { // gi.linkentity (pEntOriginal); // } // because the sytem stores sfx_t handles directly instead of the set, we have to reget the set's sfx_t... // if (pEnt->s.eType == ET_MOVER && pEnt->s.loopSound>0) { if ( VALIDSTRING( pEnt->soundSet )) { extern int BMS_MID; // from g_mover pEnt->s.loopSound = CAS_GetBModelSound( pEnt->soundSet, BMS_MID ); if (pEnt->s.loopSound == -1) { pEnt->s.loopSound = 0; } } } // NPCs and other ents store waypoints that aren't valid after a load pEnt->waypoint = 0; qboolean qbLinked = pEnt->linked; pEnt->linked = qfalse; if (qbLinked) { gi.linkentity (pEnt); } } //Read in all the entity timers TIMER_Load();//ReadEntityTimers(); if (!qbAutosave) { // now zap any g_ents that were inuse when the level was loaded, but are no longer in use in the saved version // that we've just loaded... // for (i=iPreviousEntRead+1; i<globals.num_entities; i++) { if ( g_entities[i].inuse ) // not actually necessary { G_FreeEntity(&g_entities[i]); } } //Load ICARUS information Quake3Game()->ClearEntityList(); IIcarusInterface::GetIcarus()->Load(); // check that Icarus has loaded everything it saved out by having a marker chunk after it... // static int iBlah = 1234; gi.ReadFromSaveGame('ICOK', &iBlah, sizeof(iBlah)); } if (!qbAutosave) { ReadInUseBits();//really shouldn't need to read these bits in at all, just restore them from the ents... } }
void ReadLevel(qboolean qbAutosave, qboolean qbLoadTransition) { if ( qbLoadTransition ) { // I STRONGLY SUSPECT THAT THIS WILL JUST ERR_DROP BECAUSE OF THE LOAD SWAPPING OF THE CHUNK-ORDER // BELOW BETWEEN OBJECTIVES AND LEVEL_LOCALS, SO I'M GUESSING THIS IS SOME OLD EF1 JUNK? // IN ANY CASE, LET'S MAKE SURE... // -ste (no idea who wrote the comment stuff below, did it ever work?) // assert(0); // //loadtransitions do not need to read the objectives and client data from the level they're going to //In a loadtransition, client data is carried over on the server and will be stomped later anyway. //The objective info (in client->sess data), however, is read in from G_ReadSessionData which is called before this func, //we do NOT want to stomp that session data when doing a load transition //However, we should still save this info out because these savegames may need to be //loaded normally later- perhaps if you die and need to respawn, perhaps as some kind //of emergency savegame for resuming, etc. //SO: We read it in, but throw it away. //Read & throw away gclient info gclient_t junkClient; EvaluateFields(savefields_gClient, (byte *)&junkClient, (byte *)&level.clients[0], 'GCLI', sizeof(*level.clients), qtrue);//qfalse); ReadLevelLocals(); // level_locals_t level //Read & throw away objective info objectives_t junkObj[MAX_MISSION_OBJ]; gi.ReadFromSaveGame('OBJT', (void *) &junkObj, 0); } else { if (!qbAutosave )//always load the client unless it's an autosave { assert(level.maxclients == 1); // I'll need to know if this changes, otherwise I'll need to change the way things work gclient_t GClient; EvaluateFields(savefields_gClient, (byte *)&GClient, (byte *)&level.clients[0], 'GCLI', sizeof(*level.clients), qtrue);//qfalse); level.clients[0] = GClient; // struct copy ReadLevelLocals(); // level_locals_t level } OBJ_LoadObjectiveData();//loads mission objectives AND tactical info } FX_Read(); ///////////// ReadGEntities(qbAutosave); Quake3Game()->VariableLoad(); G_LoadSave_ReadMiscData(); extern void CG_ReadTheEvilCGHackStuff(void); CG_ReadTheEvilCGHackStuff(); // (Do NOT put any read-code below this line) // // check that the whole file content was loaded by specifically requesting an end-marker... // static int iDONE = 1234; gi.ReadFromSaveGame('DONE', &iDONE, sizeof(iDONE)); }