// Copy from TeleporterHelper, but uses a different strategy so they don't spawn on top of the person public static Vector3?FindSafeTeleportDestination(Vector3 characterFootPosition, CharacterBody characterBodyOrPrefabComponent, Xoroshiro128Plus rng) { Vector3? result = null; SpawnCard spawnCard = ScriptableObject.CreateInstance <SpawnCard>(); spawnCard.hullSize = characterBodyOrPrefabComponent.hullClassification; //spawnCard.nodeGraphType = MapNodeGroup.GraphType.Ground; spawnCard.prefab = Resources.Load <GameObject>("SpawnCards/HelperPrefab"); DirectorPlacementRule placementRule = new DirectorPlacementRule { placementMode = DirectorPlacementRule.PlacementMode.Approximate, position = characterFootPosition }; DirectorCore.GetMonsterSpawnDistance(DirectorCore.MonsterSpawnDistance.Close, out placementRule.minDistance, out placementRule.maxDistance); GameObject gameObject = DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(spawnCard, placementRule, rng)); if (gameObject) { result = new Vector3?(gameObject.transform.position); Destroy(gameObject); } Destroy(spawnCard); return(result); }
private static void CreateEclipseDoppelganger(CharacterMaster master, Xoroshiro128Plus rng) { var card = DoppelgangerSpawnCard.FromMaster(master); if (card is null) { return; } if (card.prefab is null) { card.prefab = MasterCatalog.GetMasterPrefab(defaultMasterIndex); } Transform spawnOnTarget; DirectorCore.MonsterSpawnDistance input; if (TeleporterInteraction.instance) { spawnOnTarget = TeleporterInteraction.instance.transform; input = DirectorCore.MonsterSpawnDistance.Close; } else { spawnOnTarget = master.GetBody().coreTransform; input = DirectorCore.MonsterSpawnDistance.Far; } DirectorPlacementRule directorPlacementRule = new DirectorPlacementRule { spawnOnTarget = spawnOnTarget, placementMode = DirectorPlacementRule.PlacementMode.NearestNode }; DirectorCore.GetMonsterSpawnDistance(input, out directorPlacementRule.minDistance, out directorPlacementRule.maxDistance); DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(card, directorPlacementRule, rng); directorSpawnRequest.teamIndexOverride = new TeamIndex?(TeamIndex.Monster); directorSpawnRequest.ignoreTeamMemberLimit = true; CombatSquad squad = null; DirectorSpawnRequest directorSpawnRequest2 = directorSpawnRequest; directorSpawnRequest2.onSpawnedServer = DelegateHelper.Combine(directorSpawnRequest2.onSpawnedServer, (res) => { if (squad is null) { squad = UnityEngine.Object.Instantiate <GameObject>(Resources.Load <GameObject>("Prefabs/NetworkedObjects/Encounters/ShadowCloneEncounter")).GetComponent <CombatSquad>(); } squad.AddMember(res.spawnedInstance.GetComponent <CharacterMaster>()); }); DirectorCore.instance.TrySpawnObject(directorSpawnRequest); if (squad is not null) { NetworkServer.Spawn(squad.gameObject); } UnityEngine.Object.Destroy(card); }
public bool AttemptSpawnOnTarget(On.RoR2.CombatDirector.orig_AttemptSpawnOnTarget orig, CombatDirector self, Transform spawnTarget, DirectorPlacementRule.PlacementMode placementMode) { //this.GetComponent< behaviourName as MonoBehaviour> if (self.gameObject == this.gameObject) { var credit = self.monsterCredit; var monsterCards = self.monsterCards; //MoreShrines.Print("We good?"); if (!this.cardPoolInitialized) { List <CardPool> cardPools = new List <CardPool>(); foreach (var category in monsterCards.categories) { foreach (var card in category.cards) { if (cardPools.Any(pool => pool.cost == card.cost)) { cardPools.Find(pool => pool.cost == card.cost).cards.Add(card); } else { var pool = new CardPool(); pool.cost = card.cost; pool.cards.Add(card); cardPools.Add(pool); } } } cardPoolInitialized = true; cardPools.Sort((item1, item2) => { return(item1.cost.CompareTo(item2.cost)); }); var poolIndex = 0; CardPool currentBasePool = cardPools[0]; foreach (var pool in cardPools) { if (pool.cost * countToSpawn < credit) { currentBasePool = pool; } else { break; } poolIndex++; } MoreShrines.Print("Preparing to spawn " + countToSpawn + " monsters."); CardPool buffPool = cardPools[0]; var buffCount = 0; for (var i = 0; i < countToSpawn; i++) { var count = countToSpawn - i; if (cardPools.Count > poolIndex + 1) { if (((countToSpawn - count) * currentBasePool.cost) + (count * cardPools[poolIndex + 1].cost) < credit) { buffPool = cardPools[poolIndex + 1]; buffCount++; } } } for (var i = 0; i < countToSpawn - buffCount; i++) { finalSpawnOrder.Add(currentBasePool); } for (var i = 0; i < buffCount; i++) { finalSpawnOrder.Add(buffPool); } } // if (finalSpawnOrder.Count > 0) { self.currentMonsterCard = finalSpawnOrder[0].cards[Random.Range(0, finalSpawnOrder[0].cards.Count - 1)]; SpawnCard spawnCard = self.currentMonsterCard.spawnCard; DirectorPlacementRule directorPlacementRule = new DirectorPlacementRule { placementMode = placementMode, spawnOnTarget = spawnTarget, preventOverhead = self.currentMonsterCard.preventOverhead }; DirectorCore.GetMonsterSpawnDistance(self.currentMonsterCard.spawnDistance, out directorPlacementRule.minDistance, out directorPlacementRule.maxDistance); directorPlacementRule.minDistance *= self.spawnDistanceMultiplier; DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(spawnCard, directorPlacementRule, self.rng); directorSpawnRequest.ignoreTeamMemberLimit = self.ignoreTeamSizeLimit; directorSpawnRequest.teamIndexOverride = new TeamIndex?(self.teamIndex); directorSpawnRequest.onSpawnedServer = new Action <SpawnCard.SpawnResult>(onCardSpawned); if (!DirectorCore.instance.TrySpawnObject(directorSpawnRequest)) { /* * Debug.LogFormat("Spawn card {0} failed to spawn. Aborting cost procedures.", new object[] * { * spawnCard * });*/ self.enabled = false; return(false); } } else { self.enabled = false; return(false); } self.spawnCountInCurrentWave += 1; return(true); } else { return(orig(self, spawnTarget, placementMode)); } }