// This method is a modified version of vanilla, doing the same checks and balances. However, we do use the player position a bit more, and we change which biome spawning group we // will use, when below the terrain. public static void SpawnUpdate(string _spawnerName, bool _bSpawnEnemyEntities, ChunkAreaBiomeSpawnData _chunkBiomeSpawnData, ref List <Entity> spawnNearList, ref int lastClassId) { if (_chunkBiomeSpawnData == null) { return; } if (_bSpawnEnemyEntities) { if (GameStats.GetInt(EnumGameStats.EnemyCount) >= GamePrefs.GetInt(EnumGamePrefs.MaxSpawnedZombies)) { _bSpawnEnemyEntities = false; } else if (GameManager.Instance.World.aiDirector.BloodMoonComponent.BloodMoonActive) { _bSpawnEnemyEntities = false; } } if (!_bSpawnEnemyEntities && GameStats.GetInt(EnumGameStats.AnimalCount) >= GamePrefs.GetInt(EnumGamePrefs.MaxSpawnedAnimals)) { return; } bool flag = false; List <EntityPlayer> players = GameManager.Instance.World.GetPlayers(); // Player Position. Vector3 position = Vector3.zero; Rect rect = new Rect(1, 1, 1, 1); for (int i = 0; i < players.Count; i++) { if (players[i].Spawned) { position = players[i].GetPosition(); rect = new Rect(position.x - 40f, position.z - 40f, 80f, 20f); if (rect.Overlaps(_chunkBiomeSpawnData.area)) { flag = true; break; } } } // No valid player position. if (position == Vector3.zero) { return; } // Don't allow above ground spawning. Vector3i playerPosition = new Vector3i(position); float offSet = GameManager.Instance.World.GetTerrainHeight(playerPosition.x, playerPosition.z); if (offSet <= playerPosition.y) { return; } int minDistance = _bSpawnEnemyEntities ? 28 : 48; int maxDistance = _bSpawnEnemyEntities ? 54 : 70; Vector3 vector; if (!flag || !FindRandomSpawnPointNearPositionUnderground(rect, minDistance, maxDistance, false, out vector, playerPosition)) { return; } // Mob is above terrain; ignore. if (vector.y > offSet) { return; } BiomeDefinition biome = GameManager.Instance.World.Biomes.GetBiome(_chunkBiomeSpawnData.biomeId); if (biome == null) { return; } // Customize which spawning.xml entry to we want to use for spawns. String CaveType = "Cave"; // Search for the biome_Cave spawn group. If not found, load the generic Cave one. BiomeSpawnEntityGroupList biomeSpawnEntityGroupList = BiomeSpawningClass.list[biome.m_sBiomeName + "_Cave"]; if (biomeSpawnEntityGroupList == null) { biomeSpawnEntityGroupList = BiomeSpawningClass.list["Cave"]; } // if we are below 30, look for the biome specific deep cave, then deep cave if its not set. if (vector.y < 30) { CaveType = "DeepCave"; biomeSpawnEntityGroupList = BiomeSpawningClass.list[biome.m_sBiomeName + "_DeepCave"]; if (biomeSpawnEntityGroupList == null) { biomeSpawnEntityGroupList = BiomeSpawningClass.list["DeepCave"]; } } if (biomeSpawnEntityGroupList == null) { return; } EDaytime edaytime = GameManager.Instance.World.IsDaytime() ? EDaytime.Day : EDaytime.Night; GameRandom gameRandom = GameManager.Instance.World.GetGameRandom(); string entityGroupName = null; int num = -1; int num2 = gameRandom.RandomRange(biomeSpawnEntityGroupList.list.Count); int j = 0; while (j < 5) { BiomeSpawnEntityGroupData biomeSpawnEntityGroupData = biomeSpawnEntityGroupList.list[num2]; if (biomeSpawnEntityGroupData.daytime == EDaytime.Any || biomeSpawnEntityGroupData.daytime == edaytime) { bool flag2 = EntityGroups.IsEnemyGroup(biomeSpawnEntityGroupData.entityGroupRefName); if (!flag2 || _bSpawnEnemyEntities) { int num3 = biomeSpawnEntityGroupData.maxCount; if (flag2) { num3 = EntitySpawner.ModifySpawnCountByGameDifficulty(num3); } entityGroupName = biomeSpawnEntityGroupData.entityGroupRefName + "_" + biomeSpawnEntityGroupData.daytime.ToStringCached <EDaytime>() + "_" + CaveType; ulong respawnLockedUntilWorldTime = _chunkBiomeSpawnData.GetRespawnLockedUntilWorldTime(entityGroupName); if (respawnLockedUntilWorldTime <= 0UL || GameManager.Instance.World.worldTime >= respawnLockedUntilWorldTime) { if (respawnLockedUntilWorldTime > 0UL) { _chunkBiomeSpawnData.ClearRespawnLocked(entityGroupName); } if (_chunkBiomeSpawnData.GetEntitiesSpawned(entityGroupName) < num3) { num = num2; break; } } } } j++; num2 = (num2 + 1) % biomeSpawnEntityGroupList.list.Count; } if (num < 0) { //Debug.Log("max spawn reached: " + entityGroupName); return; } Bounds bb = new Bounds(vector, new Vector3(4f, 2.5f, 4f)); GameManager.Instance.World.GetEntitiesInBounds(typeof(Entity), bb, spawnNearList); int count = spawnNearList.Count; spawnNearList.Clear(); if (count > 0) { //Debug.Log("Spawn Count is maxed for "); return; } BiomeSpawnEntityGroupData biomeSpawnEntityGroupData2 = biomeSpawnEntityGroupList.list[num]; int randomFromGroup = EntityGroups.GetRandomFromGroup(biomeSpawnEntityGroupData2.entityGroupRefName, ref lastClassId, null); float spawnDeadChance = biomeSpawnEntityGroupData2.spawnDeadChance; _chunkBiomeSpawnData.IncEntitiesSpawned(entityGroupName); Entity entity = EntityFactory.CreateEntity(randomFromGroup, vector); entity.SetSpawnerSource(EnumSpawnerSource.Dynamic, _chunkBiomeSpawnData.chunk.Key, entityGroupName); EntityAlive myEntity = entity as EntityAlive; if (myEntity) { myEntity.SetSleeper(); } // Debug.Log("Spawning: " + myEntity.entityId + " " + vector ); GameManager.Instance.World.SpawnEntityInWorld(entity); if (spawnDeadChance > 0f && gameRandom.RandomFloat < spawnDeadChance) { entity.Kill(DamageResponse.New(true)); } GameManager.Instance.World.DebugAddSpawnedEntity(entity); }