//========================================================= // Guardar los objetos necesarios en caché. //========================================================= void CDirectorSpawn::Precache() { BaseClass::Precache(); // NPC's int pNpcs = ARRAYSIZE(iNpcs) - 1; for ( int i = 0; i < pNpcs; ++i ) { if ( iNpcs[i] == NULL_STRING ) continue; // Buscamos si hay una plantilla con este nombre. string_t NpcData = Templates_FindByTargetName(STRING(iNpcs[i])); // No, se trata de una clase. if ( NpcData == NULL_STRING ) UTIL_PrecacheOther(STRING(iNpcs[i])); else { // Guardamos en caché la plantilla. CBaseEntity *pEntity = NULL; MapEntity_ParseEntity(pEntity, STRING(NpcData), NULL); if ( pEntity != NULL ) { pEntity->Precache(); UTIL_RemoveImmediate(pEntity); } } } // JEFES int pBoss = ARRAYSIZE(iBoss) - 1; for ( int i = 0; i < pBoss; ++i ) { if ( iBoss[i] == NULL_STRING ) continue; // Buscamos si hay una plantilla con este nombre. string_t NpcData = Templates_FindByTargetName(STRING(iBoss[i])); // No, se trata de una clase. if ( NpcData == NULL_STRING ) UTIL_PrecacheOther(STRING(iBoss[i])); else { // Guardamos en caché la plantilla. CBaseEntity *pEntity = NULL; MapEntity_ParseEntity(pEntity, STRING(NpcData), NULL); if ( pEntity != NULL ) { pEntity->Precache(); UTIL_RemoveImmediate(pEntity); } } } }
//----------------------------------------------------------------------------- // Purpose: Place NPC somewhere on the perimeter of my radius. //----------------------------------------------------------------------------- void CTemplateNPCMaker::MakeNPCInRadius( void ) { if ( !CanMakeNPC(true)) return; CAI_BaseNPC *pent = NULL; CBaseEntity *pEntity = NULL; MapEntity_ParseEntity( pEntity, STRING(m_iszTemplateData), NULL ); if ( pEntity != NULL ) { pent = (CAI_BaseNPC *)pEntity; } if ( !pent ) { Warning("NULL Ent in NPCMaker!\n" ); return; } if ( !PlaceNPCInRadius( pent ) ) { // Failed to place the NPC. Abort UTIL_RemoveImmediate( pent ); return; } m_OnSpawnNPC.Set( pEntity, pEntity, this ); pent->AddSpawnFlags( SF_NPC_FALL_TO_GROUND ); pent->RemoveSpawnFlags( SF_NPC_TEMPLATE ); ChildPreSpawn( pent ); DispatchSpawn( pent ); pent->SetOwnerEntity( this ); DispatchActivate( pent ); ChildPostSpawn( pent ); m_nLiveChildren++;// count this NPC if (!(m_spawnflags & SF_NPCMAKER_INF_CHILD)) { m_nMaxNumNPCs--; if ( IsDepleted() ) { m_OnAllSpawned.FireOutput( this, this ); // Disable this forever. Don't kill it because it still gets death notices SetThink( NULL ); SetUse( NULL ); } } }
void CTemplateNPCMaker::Precache() { BaseClass::Precache(); if ( !m_iszTemplateData ) { // // This must be the first time we're activated, not a load from save game. // Look up the template in the template database. // if (!m_iszTemplateName) { Warning( "npc_template_maker %s has no template NPC!\n", STRING(GetEntityName()) ); UTIL_Remove( this ); return; } else { m_iszTemplateData = Templates_FindByTargetName(STRING(m_iszTemplateName)); if ( m_iszTemplateData == NULL_STRING ) { DevWarning( "npc_template_maker %s: template NPC %s not found!\n", STRING(GetEntityName()), STRING(m_iszTemplateName) ); UTIL_Remove( this ); return; } } } Assert( m_iszTemplateData != NULL_STRING ); // If the mapper marked this as "preload", then instance the entity preache stuff and delete the entity //if ( !HasSpawnFlags(SF_NPCMAKER_NOPRELOADMODELS) ) if ( m_iszTemplateData != NULL_STRING ) { CBaseEntity *pEntity = NULL; MapEntity_ParseEntity( pEntity, STRING(m_iszTemplateData), NULL ); if ( pEntity != NULL ) { PrecacheTemplateEntity( pEntity ); UTIL_RemoveImmediate( pEntity ); } } }
//========================================================= // Devuelve la creación de un NPC desde su clase/plantilla //========================================================= CAI_BaseNPC *CDirectorSpawn::VerifyClass(const char *pClass) { // Buscamos si hay una plantilla con este nombre. string_t NpcData = Templates_FindByTargetName(pClass); CAI_BaseNPC *pNPC = NULL; // No, se trata de una clase. if ( NpcData == NULL_STRING ) { // Creamos al NPC. pNPC = (CAI_BaseNPC *)CreateEntityByName(pClass); } else { // Creamos al NPC a partir de la plantilla. CBaseEntity *pEntity = NULL; MapEntity_ParseEntity(pEntity, STRING(NpcData), NULL); if ( pEntity != NULL ) pNPC = (CAI_BaseNPC *)pEntity; } return pNPC; }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTemplateNPCMaker::MakeNPC( void ) { // If we should be using the radius spawn method instead, do so if ( m_flRadius && HasSpawnFlags(SF_NPCMAKER_ALWAYSUSERADIUS) ) { MakeNPCInRadius(); return; } if (!CanMakeNPC( ( m_iszDestinationGroup != NULL_STRING ) )) return; CNPCSpawnDestination *pDestination = NULL; if ( m_iszDestinationGroup != NULL_STRING ) { pDestination = FindSpawnDestination(); if ( !pDestination ) { DevMsg( 2, "%s '%s' failed to find a valid spawnpoint in destination group: '%s'\n", GetClassname(), STRING(GetEntityName()), STRING(m_iszDestinationGroup) ); return; } } CAI_BaseNPC *pent = NULL; CBaseEntity *pEntity = NULL; MapEntity_ParseEntity( pEntity, STRING(m_iszTemplateData), NULL ); if ( pEntity != NULL ) { pent = (CAI_BaseNPC *)pEntity; } if ( !pent ) { Warning("NULL Ent in NPCMaker!\n" ); return; } if ( pDestination ) { pent->SetAbsOrigin( pDestination->GetAbsOrigin() ); // Strip pitch and roll from the spawner's angles. Pass only yaw to the spawned NPC. QAngle angles = pDestination->GetAbsAngles(); angles.x = 0.0; angles.z = 0.0; pent->SetAbsAngles( angles ); pDestination->OnSpawnedNPC( pent ); } else { pent->SetAbsOrigin( GetAbsOrigin() ); // Strip pitch and roll from the spawner's angles. Pass only yaw to the spawned NPC. QAngle angles = GetAbsAngles(); angles.x = 0.0; angles.z = 0.0; pent->SetAbsAngles( angles ); } m_OnSpawnNPC.Set( pEntity, pEntity, this ); if ( m_spawnflags & SF_NPCMAKER_FADE ) { pent->AddSpawnFlags( SF_NPC_FADE_CORPSE ); } pent->RemoveSpawnFlags( SF_NPC_TEMPLATE ); if ( ( m_spawnflags & SF_NPCMAKER_NO_DROP ) == false ) { pent->RemoveSpawnFlags( SF_NPC_FALL_TO_GROUND ); // don't fall, slam } ChildPreSpawn( pent ); DispatchSpawn( pent ); pent->SetOwnerEntity( this ); DispatchActivate( pent ); ChildPostSpawn( pent ); m_nLiveChildren++;// count this NPC if (!(m_spawnflags & SF_NPCMAKER_INF_CHILD)) { m_nMaxNumNPCs--; if ( IsDepleted() ) { m_OnAllSpawned.FireOutput( this, this ); // Disable this forever. Don't kill it because it still gets death notices SetThink( NULL ); SetUse( NULL ); } } }
//----------------------------------------------------------------------------- // Purpose: Spawn the entities I contain // Input : &vecOrigin - // &vecAngles - // pEntities - // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CPointTemplate::CreateInstance( const Vector &vecOrigin, const QAngle &vecAngles, CUtlVector<CBaseEntity*> *pEntities ) { // Go through all our templated map data and spawn all the entities in it int iTemplates = m_hTemplates.Count(); if ( !iTemplates ) { Msg("CreateInstance called on a point_template that has no templates: %s\n", STRING(GetEntityName()) ); return false; } // Tell the template system we're about to start a new template Templates_StartUniqueInstance(); int i; for ( i = 0; i < iTemplates; i++ ) { CBaseEntity *pEntity = NULL; char *pMapData; int iTemplateIndex = m_hTemplates[i].iTemplateIndex; // Some templates have Entity I/O connecting the entities within the template. // Unique versions of these templates need to be created whenever they're instanced. if ( Templates_IndexRequiresEntityIOFixup( iTemplateIndex ) ) { // This template requires instancing. // Create a new mapdata block and ask the template system to fill it in with // a unique version (with fixed Entity I/O connections). pMapData = Templates_GetEntityIOFixedMapData( iTemplateIndex ); } else { // Use the unmodified mapdata pMapData = (char*)STRING( Templates_FindByIndex( iTemplateIndex ) ); } // Create the entity from the mapdata MapEntity_ParseEntity( pEntity, pMapData, NULL ); if ( pEntity == NULL ) { Msg("Failed to initialize templated entity with mapdata: %s\n", pMapData ); return false; } // Get a matrix that'll convert from world to the new local space VMatrix matNewTemplateToWorld, matStoredLocalToWorld; matNewTemplateToWorld.SetupMatrixOrgAngles( vecOrigin, vecAngles ); MatrixMultiply( matNewTemplateToWorld, m_hTemplates[i].matEntityToTemplate, matStoredLocalToWorld ); // Get the world origin & angles from the stored local coordinates Vector vecNewOrigin; QAngle vecNewAngles; vecNewOrigin = matStoredLocalToWorld.GetTranslation(); MatrixToAngles( matStoredLocalToWorld, vecNewAngles ); // Set its origin & angles pEntity->SetAbsOrigin( vecNewOrigin ); pEntity->SetAbsAngles( vecNewAngles ); if ( DispatchSpawn( pEntity ) >= 0 ) { pEntities->AddToTail( pEntity ); } } // Now hookup entity heirarchy within the template int iCount = pEntities->Count(); for ( i = 0; i < iCount; i++ ) { CBaseEntity *pEntity = (*pEntities)[i]; if ( pEntity && pEntity->m_iParent != NULL_STRING ) { CBaseEntity *pParent = gEntList.FindEntityByName(NULL, pEntity->m_iParent, NULL); if ( pParent && (pParent->edict() != NULL) ) { pEntity->SetParent( pParent ); } } } return true; }
//----------------------------------------------------------------------------- // Purpose: Only called on BSP load. Parses and spawns all the entities in the BSP. // Input : pMapData - Pointer to the entity data block to parse. //----------------------------------------------------------------------------- void MapEntity_ParseAllEntities(const char *pMapData, IMapEntityFilter *pFilter, bool bActivateEntities) { VPROF("MapEntity_ParseAllEntities"); HierarchicalSpawnMapData_t *pSpawnMapData = new HierarchicalSpawnMapData_t[NUM_ENT_ENTRIES]; HierarchicalSpawn_t *pSpawnList = new HierarchicalSpawn_t[NUM_ENT_ENTRIES]; CUtlVector< CPointTemplate* > pPointTemplates; int nEntities = 0; char szTokenBuffer[MAPKEY_MAXLENGTH]; // Allow the tools to spawn different things if ( serverenginetools ) { pMapData = serverenginetools->GetEntityData( pMapData ); } // Loop through all entities in the map data, creating each. for ( ; true; pMapData = MapEntity_SkipToNextEntity(pMapData, szTokenBuffer) ) { // // Parse the opening brace. // char token[MAPKEY_MAXLENGTH]; pMapData = MapEntity_ParseToken( pMapData, token ); // // Check to see if we've finished or not. // if (!pMapData) break; if (token[0] != '{') { Error( "MapEntity_ParseAllEntities: found %s when expecting {", token); continue; } // // Parse the entity and add it to the spawn list. // CBaseEntity *pEntity; const char *pCurMapData = pMapData; pMapData = MapEntity_ParseEntity(pEntity, pMapData, pFilter); if (pEntity == NULL) continue; if (pEntity->IsTemplate()) { // It's a template entity. Squirrel away its keyvalue text so that we can // recreate the entity later via a spawner. pMapData points at the '}' // so we must add one to include it in the string. Templates_Add(pEntity, pCurMapData, (pMapData - pCurMapData) + 2); // Remove the template entity so that it does not show up in FindEntityXXX searches. UTIL_Remove(pEntity); gEntList.CleanupDeleteList(); continue; } // To if ( dynamic_cast<CWorld*>( pEntity ) ) { VPROF( "MapEntity_ParseAllEntities_SpawnWorld"); pEntity->m_iParent = NULL_STRING; // don't allow a parent on the first entity (worldspawn) DispatchSpawn(pEntity); continue; } CNodeEnt *pNode = dynamic_cast<CNodeEnt*>(pEntity); if ( pNode ) { VPROF( "MapEntity_ParseAllEntities_SpawnTransients"); // We overflow the max edicts on large maps that have lots of entities. // Nodes & Lights remove themselves immediately on Spawn(), so dispatch their // spawn now, to free up the slot inside this loop. // NOTE: This solution prevents nodes & lights from being used inside point_templates. // // NOTE: Nodes spawn other entities (ai_hint) if they need to have a persistent presence. // To ensure keys are copied over into the new entity, we pass the mapdata into the // node spawn function. if ( pNode->Spawn( pCurMapData ) < 0 ) { gEntList.CleanupDeleteList(); } continue; } if ( dynamic_cast<CLight*>(pEntity) ) { VPROF( "MapEntity_ParseAllEntities_SpawnTransients"); // We overflow the max edicts on large maps that have lots of entities. // Nodes & Lights remove themselves immediately on Spawn(), so dispatch their // spawn now, to free up the slot inside this loop. // NOTE: This solution prevents nodes & lights from being used inside point_templates. if (DispatchSpawn(pEntity) < 0) { gEntList.CleanupDeleteList(); } continue; } // Build a list of all point_template's so we can spawn them before everything else CPointTemplate *pTemplate = dynamic_cast< CPointTemplate* >(pEntity); if ( pTemplate ) { pPointTemplates.AddToTail( pTemplate ); } else { // Queue up this entity for spawning pSpawnList[nEntities].m_pEntity = pEntity; pSpawnList[nEntities].m_nDepth = 0; pSpawnList[nEntities].m_pDeferredParentAttachment = NULL; pSpawnList[nEntities].m_pDeferredParent = NULL; pSpawnMapData[nEntities].m_pMapData = pCurMapData; pSpawnMapData[nEntities].m_iMapDataLength = (pMapData - pCurMapData) + 2; nEntities++; } } // Now loop through all our point_template entities and tell them to make templates of everything they're pointing to int iTemplates = pPointTemplates.Count(); for ( int i = 0; i < iTemplates; i++ ) { VPROF( "MapEntity_ParseAllEntities_SpawnTemplates"); CPointTemplate *pPointTemplate = pPointTemplates[i]; // First, tell the Point template to Spawn if ( DispatchSpawn(pPointTemplate) < 0 ) { UTIL_Remove(pPointTemplate); gEntList.CleanupDeleteList(); continue; } pPointTemplate->StartBuildingTemplates(); // Now go through all it's templates and turn the entities into templates int iNumTemplates = pPointTemplate->GetNumTemplateEntities(); for ( int iTemplateNum = 0; iTemplateNum < iNumTemplates; iTemplateNum++ ) { // Find it in the spawn list CBaseEntity *pEntity = pPointTemplate->GetTemplateEntity( iTemplateNum ); for ( int iEntNum = 0; iEntNum < nEntities; iEntNum++ ) { if ( pSpawnList[iEntNum].m_pEntity == pEntity ) { // Give the point_template the mapdata pPointTemplate->AddTemplate( pEntity, pSpawnMapData[iEntNum].m_pMapData, pSpawnMapData[iEntNum].m_iMapDataLength ); if ( pPointTemplate->ShouldRemoveTemplateEntities() ) { // Remove the template entity so that it does not show up in FindEntityXXX searches. UTIL_Remove(pEntity); gEntList.CleanupDeleteList(); // Remove the entity from the spawn list pSpawnList[iEntNum].m_pEntity = NULL; } break; } } } pPointTemplate->FinishBuildingTemplates(); } SpawnHierarchicalList( nEntities, pSpawnList, bActivateEntities ); delete [] pSpawnMapData; delete [] pSpawnList; }
//----------------------------------------------------------------------------- // Purpose: Spawn the entities I contain // Input : &vecOrigin - // &vecAngles - // pEntities - // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CPointTemplate::CreateInstance( const Vector &vecOrigin, const QAngle &vecAngles, CUtlVector<CBaseEntity*> *pEntities ) { // Go through all our templated map data and spawn all the entities in it int iTemplates = m_hTemplates.Count(); if ( !iTemplates ) { Msg("CreateInstance called on a point_template that has no templates: %s\n", STRING(GetEntityName()) ); return false; } // Tell the template system we're about to start a new template Templates_StartUniqueInstance(); HierarchicalSpawn_t *pSpawnList = (HierarchicalSpawn_t*)stackalloc( iTemplates * sizeof(HierarchicalSpawn_t) ); int i; for ( i = 0; i < iTemplates; i++ ) { CBaseEntity *pEntity = NULL; char *pMapData; int iTemplateIndex = m_hTemplates[i].iTemplateIndex; // Some templates have Entity I/O connecting the entities within the template. // Unique versions of these templates need to be created whenever they're instanced. if ( AllowNameFixup() && Templates_IndexRequiresEntityIOFixup( iTemplateIndex ) ) { // This template requires instancing. // Create a new mapdata block and ask the template system to fill it in with // a unique version (with fixed Entity I/O connections). pMapData = Templates_GetEntityIOFixedMapData( iTemplateIndex ); } else { // Use the unmodified mapdata pMapData = (char*)STRING( Templates_FindByIndex( iTemplateIndex ) ); } // Create the entity from the mapdata MapEntity_ParseEntity( pEntity, pMapData, NULL ); if ( pEntity == NULL ) { Msg("Failed to initialize templated entity with mapdata: %s\n", pMapData ); return false; } // Get a matrix that'll convert from world to the new local space VMatrix matNewTemplateToWorld, matStoredLocalToWorld; matNewTemplateToWorld.SetupMatrixOrgAngles( vecOrigin, vecAngles ); MatrixMultiply( matNewTemplateToWorld, m_hTemplates[i].matEntityToTemplate, matStoredLocalToWorld ); // Get the world origin & angles from the stored local coordinates Vector vecNewOrigin; QAngle vecNewAngles; vecNewOrigin = matStoredLocalToWorld.GetTranslation(); MatrixToAngles( matStoredLocalToWorld, vecNewAngles ); // Set its origin & angles pEntity->SetAbsOrigin( vecNewOrigin ); pEntity->SetAbsAngles( vecNewAngles ); pSpawnList[i].m_pEntity = pEntity; pSpawnList[i].m_nDepth = 0; } SpawnHierarchicalList( iTemplates, pSpawnList, true ); for ( i = 0; i < iTemplates; ++i ) { if ( pSpawnList[i].m_pEntity ) { pEntities->AddToTail( pSpawnList[i].m_pEntity ); } } return true; }
void CNPC_CombineDropship::SpawnTroops( void ) { int i; // char szAttachmentName[ 32 ]; Vector vecLocation; QAngle vecAngles; QAngle vecSpawnAngles; // memset( szAttachmentName, 0, 32 ); vecSpawnAngles = GetLocalAngles(); vecSpawnAngles.y = UTIL_AngleMod( vecSpawnAngles.y - 180 ); vecSpawnAngles.x = 0; vecSpawnAngles.z = 0; for( i = 1 ; i <= m_soldiersToDrop ; i++ ) { // Q_snprintf( szAttachmentName,sizeof(szAttachmentName), "spot%d", i ); // GetAttachment( szAttachmentName, vecLocation, vecAngles ); vecLocation = GetAbsOrigin(); vecAngles = GetAbsAngles(); // troops spawn behind vehicle at all times Vector shipDir, shipLeft; AngleVectors( vecAngles, &shipDir, &shipLeft, NULL ); vecLocation -= shipDir * 250; // set spawn position for spawning in formation switch( i ) { case 1: vecLocation -= shipLeft * DROPSHIP_TROOP_GRID; break; case 3: vecLocation += shipLeft * DROPSHIP_TROOP_GRID; break; case 4: vecLocation -= shipDir * DROPSHIP_TROOP_GRID - shipLeft * DROPSHIP_TROOP_GRID; break; case 5: vecLocation -= shipDir * DROPSHIP_TROOP_GRID; break; case 6: vecLocation -= shipDir * DROPSHIP_TROOP_GRID + shipLeft * DROPSHIP_TROOP_GRID; } // spawn based upon template CAI_BaseNPC *pEnt = NULL; CBaseEntity *pEntity = NULL; MapEntity_ParseEntity( pEntity, STRING(m_sNPCTemplateData), NULL ); if ( pEntity != NULL ) { pEnt = (CAI_BaseNPC *)pEntity; } else { Warning("Dropship could not create template NPC\n" ); return; } pEnt->SetLocalOrigin( vecLocation ); pEnt->SetLocalAngles( vecSpawnAngles ); DispatchSpawn( pEnt ); pEnt->m_NPCState = NPC_STATE_IDLE; pEnt->SetOwnerEntity( this ); pEnt->Activate(); } }