private static StageSettings GetStageSettings(ClassicStageInfo self) { StageSettings set = new StageSettings { sceneDirectorInteractableCredits = self.sceneDirectorInteractibleCredits, sceneDirectorMonsterCredits = self.sceneDirectorMonsterCredits }; set.bonusCreditObjects = new Dictionary <GameObject, int>(); for (int i = 0; i < self.bonusInteractibleCreditObjects.Length; i++) { var bonusObj = self.bonusInteractibleCreditObjects[i]; set.bonusCreditObjects[bonusObj.objectThatGrantsPointsIfEnabled] = bonusObj.points; } set.interactableCategoryWeights = new Dictionary <InteractableCategory, float>(); var interCats = self.GetFieldValue <DirectorCardCategorySelection>("interactableCategories"); for (int i = 0; i < interCats.categories.Length; i++) { var cat = interCats.categories[i]; set.interactableCategoryWeights[GetInteractableCategory(cat.name)] = cat.selectionWeight; } set.monsterCategoryWeights = new Dictionary <MonsterCategory, float>(); var monstCats = self.GetFieldValue <DirectorCardCategorySelection>("monsterCategories"); for (int i = 0; i < monstCats.categories.Length; i++) { var cat = monstCats.categories[i]; set.monsterCategoryWeights[GetMonsterCategory(cat.name)] = cat.selectionWeight; } return(set); }
private static StageSettings GetStageSettings(ClassicStageInfo self) { var set = new StageSettings { SceneDirectorInteractableCredits = self.sceneDirectorInteractibleCredits, SceneDirectorMonsterCredits = self.sceneDirectorMonsterCredits, BonusCreditObjects = new Dictionary <GameObject, int>() }; foreach (var bonusObj in self.bonusInteractibleCreditObjects) { set.BonusCreditObjects[bonusObj.objectThatGrantsPointsIfEnabled] = bonusObj.points; } set.InteractableCategoryWeights = new Dictionary <InteractableCategory, float>(); var interCats = self.GetFieldValue <DirectorCardCategorySelection>("interactableCategories"); foreach (var cat in interCats.categories) { set.InteractableCategoryWeights[GetInteractableCategory(cat.name)] = cat.selectionWeight; } set.MonsterCategoryWeights = new Dictionary <MonsterCategory, float>(); var monstCats = self.GetFieldValue <DirectorCardCategorySelection>("monsterCategories"); foreach (var cat in monstCats.categories) { set.MonsterCategoryWeights[GetMonsterCategory(cat.name)] = cat.selectionWeight; } return(set); }
private static void SpawnsCore_familyEdits1(ClassicStageInfo stageInfo, Run runInstance, ClassicStageInfo.MonsterFamily[] possibleFamilies) { if (runInstance.selectedDifficulty < DifficultyIndex.Hard && runInstance is not EclipseRun) { return; } for (Int32 i = 0; i < possibleFamilies.Length; ++i) { var family = possibleFamilies[i]; if (family.familySelectionChatString != "FAMILY_WISP") { continue; } var startCount = family.monsterFamilyCategories.categories.Length; for (Int32 j = 0; j < startCount; ++j) { var category = family.monsterFamilyCategories.categories[j]; if (category.name.ToLower() != "minibosses") { continue; } var ind = category.cards.Length; Array.Resize <DirectorCard>(ref category.cards, ind + 1); category.cards[ind] = ArW_dirCard; family.monsterFamilyCategories.categories[j] = category; break; } possibleFamilies[i] = family; break; } }
private static void SetStageSettings(ClassicStageInfo self, StageSettings set) { self.sceneDirectorInteractibleCredits = set.SceneDirectorInteractableCredits; self.sceneDirectorMonsterCredits = set.SceneDirectorMonsterCredits; var keys = set.BonusCreditObjects.Keys.ToArray(); var bonuses = new ClassicStageInfo.BonusInteractibleCreditObject[keys.Length]; for (int i = 0; i < keys.Length; i++) { bonuses[i] = new ClassicStageInfo.BonusInteractibleCreditObject { objectThatGrantsPointsIfEnabled = keys[i], points = set.BonusCreditObjects[keys[i]] }; } self.bonusInteractibleCreditObjects = bonuses; var interCats = self.GetFieldValue <DirectorCardCategorySelection>("interactableCategories"); for (int i = 0; i < interCats.categories.Length; i++) { var cat = interCats.categories[i]; InteractableCategory intCat = GetInteractableCategory(cat.name); cat.selectionWeight = set.InteractableCategoryWeights[intCat]; interCats.categories[i] = cat; } var monstCats = self.GetFieldValue <DirectorCardCategorySelection>("monsterCategories"); for (int i = 0; i < monstCats.categories.Length; i++) { var cat = monstCats.categories[i]; MonsterCategory monCat = GetMonsterCategory(cat.name); cat.selectionWeight = set.MonsterCategoryWeights[monCat]; monstCats.categories[i] = cat; } }
private static void ApplySettingsChanges(ClassicStageInfo self, StageInfo stageInfo) { StageSettings settings = GetStageSettings(self); StageSettingsActions?.Invoke(settings, stageInfo); SetStageSettings(self, settings); }
private static void ApplyMonsterChanges(ClassicStageInfo self, StageInfo stage) { var monsters = self.GetFieldValue <DirectorCardCategorySelection>("monsterCategories"); var monsterCards = new List <DirectorCardHolder>(); foreach (var cat in monsters.categories) { MonsterCategory monstCat = GetMonsterCategory(cat.name); InteractableCategory interCat = GetInteractableCategory(cat.name); foreach (var t in cat.cards) { monsterCards.Add(new DirectorCardHolder { InteractableCategory = interCat, MonsterCategory = monstCat, Card = t }); } } MonsterActions?.Invoke(monsterCards, stage); var monsterBasic = new List <DirectorCard>(); var monsterSub = new List <DirectorCard>(); var monsterChamp = new List <DirectorCard>(); foreach (var hold in monsterCards) { switch (hold.MonsterCategory) { case MonsterCategory.BasicMonsters: monsterBasic.Add(hold.Card); break; case MonsterCategory.Champions: monsterChamp.Add(hold.Card); break; case MonsterCategory.Minibosses: monsterSub.Add(hold.Card); break; } } for (int i = 0; i < monsters.categories.Length; i++) { DirectorCardCategorySelection.Category cat = monsters.categories[i]; switch (cat.name) { case "Champions": cat.cards = monsterChamp.ToArray(); break; case "Minibosses": cat.cards = monsterSub.ToArray(); break; case "Basic Monsters": cat.cards = monsterBasic.ToArray(); break; } monsters.categories[i] = cat; } }
internal static void ApplyChanges(this ClassicStageInfo self) { var stageInfo = GetStageInfo(self); ApplySettingsChanges(self, stageInfo); ApplyMonsterChanges(self, stageInfo); ApplyInteractableChanges(self, stageInfo); ApplyFamilyChanges(self, stageInfo); }
private static void ApplyFamilyChanges(ClassicStageInfo self, StageInfo stage) { var familyHolds = self.possibleMonsterFamilies.Select(GetMonsterFamilyHolder).ToList(); FamilyActions?.Invoke(familyHolds, stage); self.possibleMonsterFamilies = new ClassicStageInfo.MonsterFamily[familyHolds.Count]; for (int i = 0; i < familyHolds.Count; i++) { self.possibleMonsterFamilies[i] = GetMonsterFamily(familyHolds[i]); } }
private void SpawnsCore_monsterEdits(ClassicStageInfo stageInfo, Run runInstance, DirectorCardCategorySelection monsterSelection) { Log.Warning("edits"); Log.Warning(monsterSelection.name); if (monsterSelection.name == "dccsSkyMeadowMonsters") { Log.Warning("IsRightMap"); //monsterSelection.RemoveCardsThatFailFilter( ( card ) => !( card.spawnCard.name.Contains( "Grandparent" ) ) ); _ = monsterSelection.AddCard(0, this.dirCard); _ = monsterSelection.AddCard(1, this.dirCard); _ = monsterSelection.AddCard(2, this.dirCard); } }
private static void StageAwake(On.RoR2.ClassicStageInfo.orig_Awake orig, ClassicStageInfo self) { var stage = GetStage(self); ApplySettingsChanges(self, stage); ApplyMonsterChanges(self, stage); ApplyInteractableChanges(self, stage); ApplyFamilyChanges(self, stage); orig(self); }
private void SpawnsCore_monsterEdits(ClassicStageInfo stageInfo, Run runInstance, DirectorCardCategorySelection monsterSelection) { for (Int32 i = 0; i < monsterSelection.categories.Length; ++i) { ref var cat = ref monsterSelection.categories[i]; for (Int32 j = 0; j < cat.cards.Length; ++j) { var card = cat.cards[j]; if (card.spawnCard is CharacterSpawnCard csc && csc.name?.ToLower() == "cscelectricworm") { csc.noElites = false; } } }
private static void ApplyFamilyChanges(ClassicStageInfo self, StageInfo stage) { List <MonsterFamilyHolder> familyHolds = new List <MonsterFamilyHolder>(); for (int i = 0; i < self.possibleMonsterFamilies.Length; i++) { familyHolds.Add(GetMonsterFamilyHolder(self.possibleMonsterFamilies[i])); } familyActions?.Invoke(familyHolds, stage); self.possibleMonsterFamilies = new ClassicStageInfo.MonsterFamily[familyHolds.Count]; for (int i = 0; i < familyHolds.Count; i++) { Debug.Log(i); self.possibleMonsterFamilies[i] = GetMonsterFamily(familyHolds[i]); } }
public static GameObject CreateGameObject() { GameObject gameObject = null; if (NetworkServer.active) { ClassicStageInfo component = SceneInfo.instance.GetComponent <ClassicStageInfo>(); DirectorCard directorCard = CommonUtil.SelectCard(component.interactableSelection, 100); while (!directorCard.spawnCard.name.Contains("Barrel")) { directorCard = CommonUtil.SelectCard(component.interactableSelection, 100); } gameObject = directorCard.spawnCard.DoSpawn(Vector3.zero, Quaternion.identity); } return(gameObject); }
private static void SceneDirector_Start(Action <RoR2.SceneDirector> orig, SceneDirector self) { if (NetworkServer.active) { ClassicStageInfo stageInfo = SceneInfo.instance.GetComponent <ClassicStageInfo>(); foreach (InteractableInfo interactable in registeredInteractables) { if (interactable.multiplayerOnly && RoR2Application.isInMultiPlayer || !interactable.multiplayerOnly) { //Debug.Log("Trying to add " + interactable.directorCard.spawnCard.prefab.name + " to " + SceneManager.GetActiveScene().name); if (interactable.scenes.Contains(SceneManager.GetActiveScene().name)) { stageInfo.interactableCategories.AddCard((int)interactable.category, interactable.directorCard); } } } } orig(self); }
static void DisableDefaultSpawn(On.RoR2.SceneDirector.orig_Start orig, SceneDirector self) { if (NetworkServer.active) { ClassicStageInfo sceneInfo = SceneInfo.instance.GetComponent <ClassicStageInfo>(); //Disables default interactibles spawning if (VoteAPI.VoteResults.HasVote(Settings.CustomInteractablesSpawner.Item2)) { sceneInfo.sceneDirectorInteractibleCredits = 0; sceneInfo.bonusInteractibleCreditObjects = null; } //Disables default mob spawning if (!VoteAPI.VoteResults.HasVote(Settings.MobSpawn.Item2)) { sceneInfo.sceneDirectorMonsterCredits = 0; } } orig(self); }
private static void SpawnsCore_monsterEdits1(ClassicStageInfo stageInfo, Run runInstance, DirectorCardCategorySelection monsterSelection) { if (runInstance.selectedDifficulty < DifficultyIndex.Hard && runInstance is not EclipseRun) { return; } for (Int32 i = 0; i < monsterSelection.categories.Length; ++i) { var category = monsterSelection.categories[i]; if (category.name.ToLower() != "minibosses") { continue; } var ind = category.cards.Length; Array.Resize <DirectorCard>(ref category.cards, ind + 1); category.cards[ind] = ArW_dirCard; monsterSelection.categories[i] = category; break; } }
static bool Prefix(SceneDirector __instance, ref Xoroshiro128Plus ___rng, ref int ___interactableCredit, ref int ___monsterCredit) { ___rng = new Xoroshiro128Plus((ulong)Run.instance.stageRng.nextUint); float num = 0.5f + (float)Run.instance.participatingPlayerCount * 0.5f; num *= LevelIntrInVar.Stacks; ClassicStageInfo component = SceneInfo.instance.GetComponent <ClassicStageInfo>(); if (component) { ___interactableCredit = (int)((float)component.sceneDirectorInteractibleCredits * num); Debug.LogFormat("Spending {0} credits on interactables...", new object[] { ___interactableCredit }); ___monsterCredit = (int)((float)component.sceneDirectorMonsterCredits * Run.instance.difficultyCoefficient) * LevelMonsterInVar.Stacks; } typeof(SceneDirector).Raise("onPrePopulateSceneServer", __instance); new Traverse(__instance).Method("PopulateScene").GetValue(); typeof(SceneDirector).Raise("onPostPopulateSceneServer", __instance); return(false); }
private void SpawnsCore_monsterEdits1(ClassicStageInfo stageInfo, Run runInstance, DirectorCardCategorySelection monsterSelection) { foreach (var m in monsterSelection.categories) { if (m.name.Contains("ions")) { foreach (var n in m.cards) { //Main.LogW( n.spawnCard.name ); if (n.spawnCard.name != "cscBeetleQueen") { n.selectionWeight = 0; } else { var master = (n.spawnCard as CharacterSpawnCard).prefab; foreach (var v in master.GetComponents <RoR2.CharacterAI.AISkillDriver>()) { if (v.skillSlot == SkillSlot.Secondary) { v.maxUserHealthFraction = 0f; v.minUserHealthFraction = 0f; } } master.GetComponent <CharacterMaster>().bodyPrefab.AddComponent <TimeThing>(); } } } else { foreach (var n in m.cards) { var body = n.spawnCard.prefab.GetComponent <CharacterMaster>().bodyPrefab.GetComponent <CharacterBody>(); body.baseDamage = 0f; body.levelDamage = 0f; } } } }
private static void ApplyMonsterChanges(ClassicStageInfo self, StageInfo stage) { var monsters = self.GetFieldValue <DirectorCardCategorySelection>("monsterCategories"); List <DirectorCardHolder> monsterCards = new List <DirectorCardHolder>(); for (int i = 0; i < monsters.categories.Length; i++) { DirectorCardCategorySelection.Category cat = monsters.categories[i]; MonsterCategory monstCat = GetMonsterCategory(cat.name); InteractableCategory interCat = GetInteractableCategory(cat.name); for (int j = 0; j < cat.cards.Length; j++) { monsterCards.Add(new DirectorCardHolder { interactableCategory = interCat, monsterCategory = monstCat, card = cat.cards[j] }); } } monsterActions?.Invoke(monsterCards, stage); DirectorCard[] monsterBasic = new DirectorCard[0]; DirectorCard[] monsterSub = new DirectorCard[0]; DirectorCard[] monsterChamp = new DirectorCard[0]; for (int i = 0; i < monsterCards.Count; i++) { DirectorCardHolder hold = monsterCards[i]; switch (hold.monsterCategory) { default: Debug.Log("Wtf are you doing..."); break; case MonsterCategory.BasicMonsters: AddToArray <DirectorCard>(ref monsterBasic, hold.card); break; case MonsterCategory.Champions: AddToArray <DirectorCard>(ref monsterChamp, hold.card); break; case MonsterCategory.Minibosses: AddToArray <DirectorCard>(ref monsterSub, hold.card); break; } } for (int i = 0; i < monsters.categories.Length; i++) { DirectorCardCategorySelection.Category cat = monsters.categories[i]; switch (cat.name) { default: Debug.Log(cat.name); break; case "Champions": cat.cards = monsterChamp; break; case "Minibosses": cat.cards = monsterSub; break; case "Basic Monsters": cat.cards = monsterBasic; break; } monsters.categories[i] = cat; } }
internal static void ForceFamilyEvent(On.RoR2.ClassicStageInfo.orig_RebuildCards orig, ClassicStageInfo self) { var originalVal = ClassicStageInfo.monsterFamilyChance; ClassicStageInfo.monsterFamilyChance = 1; orig(self); ClassicStageInfo.monsterFamilyChance = originalVal; On.RoR2.ClassicStageInfo.RebuildCards -= ForceFamilyEvent; }
private static void ApplyInteractableChanges(ClassicStageInfo self, StageInfo stage) { var interactables = self.GetFieldValue <DirectorCardCategorySelection>("interactableCategories"); var interactableCards = new List <DirectorCardHolder>(); foreach (var cat in interactables.categories) { MonsterCategory monstCat = GetMonsterCategory(cat.name); InteractableCategory interCat = GetInteractableCategory(cat.name); foreach (var t in cat.cards) { interactableCards.Add(new DirectorCardHolder { InteractableCategory = interCat, MonsterCategory = monstCat, Card = t }); } } InteractableActions?.Invoke(interactableCards, stage); var interChests = new List <DirectorCard>(); var interBarrels = new List <DirectorCard>(); var interShrines = new List <DirectorCard>(); var interDrones = new List <DirectorCard>(); var interMisc = new List <DirectorCard>(); var interRare = new List <DirectorCard>(); var interDupe = new List <DirectorCard>(); foreach (var hold in interactableCards) { switch (hold.InteractableCategory) { case InteractableCategory.None: R2API.Logger.LogWarning("InteractableCategory from DirectorCardHolder is None !"); break; case InteractableCategory.Chests: interChests.Add(hold.Card); break; case InteractableCategory.Barrels: interBarrels.Add(hold.Card); break; case InteractableCategory.Drones: interDrones.Add(hold.Card); break; case InteractableCategory.Duplicator: interDupe.Add(hold.Card); break; case InteractableCategory.Misc: interMisc.Add(hold.Card); break; case InteractableCategory.Rare: interRare.Add(hold.Card); break; case InteractableCategory.Shrines: interShrines.Add(hold.Card); break; } } for (int i = 0; i < interactables.categories.Length; i++) { DirectorCardCategorySelection.Category cat = interactables.categories[i]; switch (cat.name) { case "Chests": cat.cards = interChests.ToArray(); break; case "Barrels": cat.cards = interBarrels.ToArray(); break; case "Shrines": cat.cards = interShrines.ToArray(); break; case "Drones": cat.cards = interDrones.ToArray(); break; case "Misc": cat.cards = interMisc.ToArray(); break; case "Rare": cat.cards = interRare.ToArray(); break; case "Duplicator": cat.cards = interDupe.ToArray(); break; } interactables.categories[i] = cat; } }
public static void AddHooks() { // Ugh. On.RoR2.CharacterAI.BaseAI.OnBodyLost += (orig, self, body) => { if (self.name.Equals("PlayerBot")) { // Reset player bot state when body is lost so errors dont pop up self.stateMachine.SetNextState(EntityStateCatalog.InstantiateState(self.scanState)); return; } orig(self, body); }; // Random fix to make captains spawnable without errors in PlayerMode, theres probably a better way of doing this too On.RoR2.CaptainDefenseMatrixController.OnServerMasterSummonGlobal += (orig, self, summonReport) => { if (self.GetFieldValue <CharacterBody>("characterBody") == null) { return; } orig(self, summonReport); }; // Maybe there is a better way to do this if (PlayerBotManager.ShowNameplates.Value && !PlayerBotManager.PlayerMode.Value) { IL.RoR2.TeamComponent.SetupIndicator += il => { ILCursor c = new ILCursor(il); c.GotoNext(x => x.MatchCallvirt <CharacterBody>("get_isPlayerControlled")); bool isPlayerBot = false; c.EmitDelegate <Func <CharacterBody, CharacterBody> >(x => { isPlayerBot = x.master.name.Equals("PlayerBot"); return(x); } ); c.Index += 1; c.EmitDelegate <Func <bool, bool> >(x => { if (isPlayerBot) { return(true); } return(x); } ); }; } if (!PlayerBotManager.PlayerMode.Value && PlayerBotManager.AutoPurchaseItems.Value) { // Give bots money On.RoR2.TeamManager.GiveTeamMoney += (orig, self, teamIndex, money) => { orig(self, teamIndex, money); if (PlayerBotManager.playerbots.Count > 0) { int num = Run.instance ? Run.instance.livingPlayerCount : 0; if (num != 0) { money = (uint)Mathf.CeilToInt(money / (float)num); } foreach (GameObject playerbot in PlayerBotManager.playerbots) { if (!playerbot) { continue; } CharacterMaster master = playerbot.GetComponent <CharacterMaster>(); if (master && !master.IsDeadAndOutOfLivesServer() && master.teamIndex == teamIndex) { master.GiveMoney(money); } } } }; } if (PlayerBotManager.AutoPurchaseItems.Value) { On.RoR2.Run.BeginStage += (orig, self) => { foreach (GameObject playerbot in PlayerBotManager.playerbots.ToArray()) { if (!playerbot) { PlayerBotManager.playerbots.Remove(playerbot); continue; } ItemManager itemManager = playerbot.GetComponent <ItemManager>(); if (itemManager) { itemManager.ResetPurchases(); itemManager.master.money = 0; } } orig(self); }; } On.RoR2.Stage.Start += (orig, self) => { orig(self); if (NetworkServer.active) { if (PlayerBotManager.PlayerMode.Value) { foreach (GameObject playerbot in PlayerBotManager.playerbots.ToArray()) { if (!playerbot) { PlayerBotManager.playerbots.Remove(playerbot); continue; } CharacterMaster master = playerbot.GetComponent <CharacterMaster>(); if (master) { Stage.instance.RespawnCharacter(master); } } } // Spawn starting bots if (Run.instance.stageClearCount == 0) { if (PlayerBotManager.InitialRandomBots.Value > 0) { PlayerBotManager.SpawnRandomPlayerbots(NetworkUser.readOnlyInstancesList[0].master, PlayerBotManager.InitialRandomBots.Value); } for (int randomSurvivorsIndex = 0; randomSurvivorsIndex < PlayerBotManager.InitialBots.Length; randomSurvivorsIndex++) { if (PlayerBotManager.InitialBots[randomSurvivorsIndex].Value > 0) { PlayerBotManager.SpawnPlayerbots(NetworkUser.readOnlyInstancesList[0].master, PlayerBotManager.RandomSurvivorsList[randomSurvivorsIndex], PlayerBotManager.InitialBots[randomSurvivorsIndex].Value); } } } } }; // Fix custom targets On.RoR2.CharacterAI.BaseAI.Target.GetBullseyePosition += Hook_GetBullseyePosition; if (PlayerBotManager.PlayerMode.Value) { On.RoR2.SceneDirector.PlaceTeleporter += (orig, self) => { if (PlayerBotManager.DontScaleInteractables.Value) { int count = PlayerCharacterMasterController.instances.Count((PlayerCharacterMasterController v) => v.networkUser); float num = 0.5f + (float)count * 0.5f; ClassicStageInfo component = SceneInfo.instance.GetComponent <ClassicStageInfo>(); int credit = (int)((float)component.sceneDirectorInteractibleCredits * num); if (component.bonusInteractibleCreditObjects != null) { for (int i = 0; i < component.bonusInteractibleCreditObjects.Length; i++) { ClassicStageInfo.BonusInteractibleCreditObject bonusInteractibleCreditObject = component.bonusInteractibleCreditObjects[i]; if (bonusInteractibleCreditObject.objectThatGrantsPointsIfEnabled.activeSelf) { credit += bonusInteractibleCreditObject.points; } } } self.interactableCredit = credit; } else if (Run.instance.stageClearCount == 0 && PlayerBotManager.GetInitialBotCount() > 0) { int count = PlayerCharacterMasterController.instances.Count((PlayerCharacterMasterController v) => v.networkUser); count += PlayerBotManager.GetInitialBotCount(); float num = 0.5f + (float)count * 0.5f; ClassicStageInfo component = SceneInfo.instance.GetComponent <ClassicStageInfo>(); int credit = (int)((float)component.sceneDirectorInteractibleCredits * num); if (component.bonusInteractibleCreditObjects != null) { for (int i = 0; i < component.bonusInteractibleCreditObjects.Length; i++) { ClassicStageInfo.BonusInteractibleCreditObject bonusInteractibleCreditObject = component.bonusInteractibleCreditObjects[i]; if (bonusInteractibleCreditObject.objectThatGrantsPointsIfEnabled.activeSelf) { credit += bonusInteractibleCreditObject.points; } } } self.interactableCredit = credit; } orig(self); }; // Required for bots to even move, maybe switch to il later On.RoR2.PlayerCharacterMasterController.Update += (orig, self) => { if (self.name.Equals("PlayerBot")) { //self.InvokeMethod("SetBody", new object[] { self.master.GetBodyObject() }); return; } orig(self); }; IL.RoR2.UI.AllyCardManager.PopulateCharacterDataSet += il => { ILCursor c = new ILCursor(il); c.GotoNext(x => x.MatchCallvirt <CharacterMaster>("get_playerCharacterMasterController")); c.Index += 2; c.EmitDelegate <Func <bool, bool> >(x => false); }; // Spectator fix On.RoR2.CameraRigController.CanUserSpectateBody += (orig, viewer, body) => { return(body.isPlayerControlled || orig(viewer, body)); }; // Dont end game on dying if (PlayerBotManager.ContinueAfterDeath.Value) { IL.RoR2.Stage.FixedUpdate += il => { ILCursor c = new ILCursor(il); c.GotoNext(x => x.MatchCallvirt <PlayerCharacterMasterController>("get_isConnected")); c.Index += 1; c.EmitDelegate <Func <bool, bool> >(x => true); }; } } }
private static void Awake_On(HooksCore.RoR2.ClassicStageInfo.Awake.Orig orig, ClassicStageInfo self) { if (loaded) { monsterEdits?.Invoke(self, Run.instance, self.monsterCategories); interactableEdits?.Invoke(self, Run.instance, self.interactableCategories); familyEdits?.Invoke(self, Run.instance, self.possibleMonsterFamilies); miscEdits?.Invoke(self, Run.instance); } orig(self); }
public void Awake() { SurvivorDict.Add("commando", SurvivorIndex.Commando); SurvivorDict.Add("mult", SurvivorIndex.Toolbot); SurvivorDict.Add("mul-t", SurvivorIndex.Toolbot); SurvivorDict.Add("toolbot", SurvivorIndex.Toolbot); SurvivorDict.Add("hunt", SurvivorIndex.Huntress); SurvivorDict.Add("huntress", SurvivorIndex.Huntress); SurvivorDict.Add("engi", SurvivorIndex.Engi); SurvivorDict.Add("engineer", SurvivorIndex.Engi); SurvivorDict.Add("mage", SurvivorIndex.Mage); SurvivorDict.Add("arti", SurvivorIndex.Mage); SurvivorDict.Add("artificer", SurvivorIndex.Mage); SurvivorDict.Add("merc", SurvivorIndex.Merc); SurvivorDict.Add("mercenary", SurvivorIndex.Merc); SurvivorDict.Add("rex", SurvivorIndex.Treebot); SurvivorDict.Add("treebot", SurvivorIndex.Treebot); SurvivorDict.Add("loader", SurvivorIndex.Loader); SurvivorDict.Add("acrid", SurvivorIndex.Croco); SurvivorDict.Add("croco", SurvivorIndex.Croco); // Config InitialRandomBots = Config.Wrap("Starting Bots", "StartingBots.Random", "Starting amount of bots to spawn at the start of a run. (Random)", 0); for (int i = 0; i < RandomSurvivors.Length; i++) { string name = RandomSurvivors[i].ToString(); InitialBots[i] = Config.Wrap("Starting Bots", "StartingBots." + name, "Starting amount of bots to spawn at the start of a run. (" + name + ")", 0); } AutoPurchaseItems = Config.Wrap("Bot Inventory", "AutoPurchaseItems", "Maximum amount of purchases a playerbot can do per stage. Items are purchased directly instead of from chests. (Default: true)", true); MaxBotPurchasesPerStage = Config.Wrap("Bot Inventory", "MaxBotPurchasesPerStage", "Maximum amount of putchases a playerbot can do per stage. (Default: 8)", 8); Tier1ChestBotWeight = Config.Wrap("Bot Inventory", "Tier1ChestBotWeight", "Weight of a bot picking an item from a small chest's loot table. (Default: 0.8)", 0.8f); Tier2ChestBotWeight = Config.Wrap("Bot Inventory", "Tier2ChestBotWeight", "Weight of a bot picking an item from a large chest's loot table. (Default: 0.2)", 0.2f); Tier3ChestBotWeight = Config.Wrap("Bot Inventory", "Tier3ChestBotWeight", "Weight of a bot picking an item from a legendary chest's loot table. (Default: 0)", 0f); Tier1ChestBotCost = Config.Wrap("Bot Inventory", "Tier1ChestBotCost", "Base price of a small chest for the bot. (Default: 25)", 25); Tier2ChestBotCost = Config.Wrap("Bot Inventory", "Tier2ChestBotCost", "Base price of a large chest for the bot. (Default: 50)", 50); Tier3ChestBotCost = Config.Wrap("Bot Inventory", "Tier3ChestBotCost", "Base price of a legendary chest for the bot. (Default: 400)", 400); EquipmentBuyChance = Config.Wrap("Bot Inventory", "EquipmentBuyChance", "Chance between 0 and 100 for a bot to buy from an equipment barrel instead of a tier 1 chest. Only active while the bot does not have a equipment item. (Default: 15)", 15); HostOnlySpawnBots = Config.Wrap("Misc", "HostOnlySpawnBots", "Set true so that only the host may spawn bots", true); ShowNameplates = Config.Wrap("Misc", "ShowNameplates", "Show player nameplates on playerbots if SpawnAsPlayers == false. (Host only)", true); PlayerMode = Config.Wrap("Experimental", "SpawnAsPlayers", "Makes the game treat playerbots like how regular players are treated. The bots now show up on the scoreboard, can pick up items, influence the map scaling, etc.", false); TpFix = Config.Wrap("Player Mode", "Teleport Fix", "Fixes long teleporter charging times by making the bots count towards the charging timer. Only active is PlayerMode is true.", true); DontScaleInteractables = Config.Wrap("Player Mode", "DontScaleInteractables", "Prevents interactables spawn count from scaling with bots. Only active is PlayerMode is true.", false); R2API.Utils.CommandHelper.AddToConsoleWhenReady(); // Ugh. On.RoR2.CharacterAI.BaseAI.OnBodyLost += (orig, self, body) => { if (self.name.Equals("PlayerBot")) { return; } orig(self, body); }; // Maybe there is a better way to do this if (ShowNameplates.Value && !PlayerMode.Value) { IL.RoR2.TeamComponent.SetupIndicator += il => { ILCursor c = new ILCursor(il); c.GotoNext(x => x.MatchCallvirt <CharacterBody>("get_isPlayerControlled")); bool isPlayerBot = false; c.EmitDelegate <Func <CharacterBody, CharacterBody> >(x => { isPlayerBot = x.master.name.Equals("PlayerBot"); return(x); } ); c.Index += 1; c.EmitDelegate <Func <bool, bool> >(x => { if (isPlayerBot) { return(true); } return(x); } ); }; } if (!PlayerMode.Value && AutoPurchaseItems.Value) { // Give bots money On.RoR2.TeamManager.GiveTeamMoney += (orig, self, teamIndex, money) => { orig(self, teamIndex, money); if (playerbots.Count > 0) { int num = Run.instance ? Run.instance.livingPlayerCount : 0; if (num != 0) { money = (uint)Mathf.CeilToInt(money / (float)num); } foreach (GameObject playerbot in playerbots) { if (!playerbot) { continue; } CharacterMaster master = playerbot.GetComponent <CharacterMaster>(); if (master && master.alive && master.teamIndex == teamIndex) { master.GiveMoney(money); } } } }; } if (AutoPurchaseItems.Value) { On.RoR2.Run.BeginStage += (orig, self) => { foreach (GameObject playerbot in playerbots.ToArray()) { if (!playerbot) { playerbots.Remove(playerbot); continue; } ItemManager itemManager = playerbot.GetComponent <ItemManager>(); if (itemManager) { itemManager.ResetPurchases(); itemManager.master.money = 0; } } orig(self); }; } if (PlayerMode.Value && TpFix.Value) { On.RoR2.TeleporterInteraction.GetPlayerCountInRadius += (orig, self) => { Vector3 position = self.gameObject.transform.position; float num2 = self.clearRadius * self.clearRadius; return(PlayerCharacterMasterController.instances.Count((PlayerCharacterMasterController c) => c.master.alive && (c.master.GetBody().transform.position - position).sqrMagnitude <= num2)); }; } On.RoR2.Stage.Start += (orig, self) => { orig(self); if (NetworkServer.active) { if (PlayerMode.Value) { foreach (GameObject playerbot in playerbots.ToArray()) { if (!playerbot) { playerbots.Remove(playerbot); continue; } CharacterMaster master = playerbot.GetComponent <CharacterMaster>(); if (master) { Stage.instance.RespawnCharacter(master); } } } // Spawn starting bots if (Run.instance.stageClearCount == 0) { if (InitialRandomBots.Value > 0) { SpawnRandomPlayerbots(NetworkUser.readOnlyInstancesList[0].master, InitialRandomBots.Value); } for (int randomSurvivorsIndex = 0; randomSurvivorsIndex < InitialBots.Length; randomSurvivorsIndex++) { if (InitialBots[randomSurvivorsIndex].Value > 0) { SpawnPlayerbots(NetworkUser.readOnlyInstancesList[0].master, RandomSurvivors[randomSurvivorsIndex], InitialBots[randomSurvivorsIndex].Value); } } } } }; if (PlayerMode.Value) { On.RoR2.SceneDirector.PlaceTeleporter += (orig, self) => { if (DontScaleInteractables.Value) { int count = PlayerCharacterMasterController.instances.Count((PlayerCharacterMasterController v) => v.networkUser); float num = 0.5f + (float)count * 0.5f; ClassicStageInfo component = SceneInfo.instance.GetComponent <ClassicStageInfo>(); self.SetFieldValue("interactableCredit", (int)((float)component.sceneDirectorInteractibleCredits * num)); } else if (Run.instance.stageClearCount == 0 && GetInitialBotCount() > 0) { int count = PlayerCharacterMasterController.instances.Count((PlayerCharacterMasterController v) => v.networkUser); count += GetInitialBotCount(); float num = 0.5f + (float)count * 0.5f; ClassicStageInfo component = SceneInfo.instance.GetComponent <ClassicStageInfo>(); self.SetFieldValue("interactableCredit", (int)((float)component.sceneDirectorInteractibleCredits * num)); } orig(self); }; IL.RoR2.UI.AllyCardManager.PopulateCharacterDataSet += il => { ILCursor c = new ILCursor(il); c.GotoNext(x => x.MatchCallvirt <CharacterMaster>("get_playerCharacterMasterController")); c.Index += 2; c.EmitDelegate <Func <bool, bool> >(x => false); }; } }
private static void ApplyInteractableChanges(ClassicStageInfo self, StageInfo stage) { var interactables = self.GetFieldValue <DirectorCardCategorySelection>("interactableCategories"); List <DirectorCardHolder> interactableCards = new List <DirectorCardHolder>(); for (int i = 0; i < interactables.categories.Length; i++) { DirectorCardCategorySelection.Category cat = interactables.categories[i]; MonsterCategory monstCat = GetMonsterCategory(cat.name); InteractableCategory interCat = GetInteractableCategory(cat.name); for (int j = 0; j < cat.cards.Length; j++) { interactableCards.Add(new DirectorCardHolder { interactableCategory = interCat, monsterCategory = monstCat, card = cat.cards[j] }); } } interactableActions?.Invoke(interactableCards, stage); DirectorCard[] interChests = new DirectorCard[0]; DirectorCard[] interBarrels = new DirectorCard[0]; DirectorCard[] interShrines = new DirectorCard[0]; DirectorCard[] interDrones = new DirectorCard[0]; DirectorCard[] interMisc = new DirectorCard[0]; DirectorCard[] interRare = new DirectorCard[0]; DirectorCard[] interDupe = new DirectorCard[0]; for (int i = 0; i < interactableCards.Count; i++) { DirectorCardHolder hold = interactableCards[i]; switch (hold.interactableCategory) { default: Debug.Log("Wtf are you doing..."); break; case InteractableCategory.Chests: AddToArray <DirectorCard>(ref interChests, hold.card); break; case InteractableCategory.Barrels: AddToArray <DirectorCard>(ref interBarrels, hold.card); break; case InteractableCategory.Drones: AddToArray <DirectorCard>(ref interDrones, hold.card); break; case InteractableCategory.Duplicator: AddToArray <DirectorCard>(ref interDupe, hold.card); break; case InteractableCategory.Misc: AddToArray <DirectorCard>(ref interMisc, hold.card); break; case InteractableCategory.Rare: AddToArray <DirectorCard>(ref interRare, hold.card); break; case InteractableCategory.Shrines: AddToArray <DirectorCard>(ref interShrines, hold.card); break; } } for (int i = 0; i < interactables.categories.Length; i++) { DirectorCardCategorySelection.Category cat = interactables.categories[i]; switch (cat.name) { default: Debug.Log(cat.name); break; case "Chests": cat.cards = interChests; break; case "Barrels": cat.cards = interBarrels; break; case "Shrines": cat.cards = interShrines; break; case "Drones": cat.cards = interDrones; break; case "Misc": cat.cards = interMisc; break; case "Rare": cat.cards = interRare; break; case "Duplicator": cat.cards = interDupe; break; } interactables.categories[i] = cat; } }
private static StageInfo GetStage(ClassicStageInfo stage) { StageInfo stageInfo = new StageInfo { stage = Stage.Custom, customStageName = "", }; SceneInfo info = stage.GetComponent <SceneInfo>(); if (!info) { return(stageInfo); } SceneDef scene = info.sceneDef; if (!scene) { return(stageInfo); } switch (scene.sceneName) { case "golemplains": stageInfo.stage = Stage.TitanicPlains; break; case "blackbeach": stageInfo.stage = Stage.DistantRoost; break; case "goolake": stageInfo.stage = Stage.AbandonedAqueduct; break; case "foggyswamp": stageInfo.stage = Stage.WetlandAspect; break; case "frozenwall": stageInfo.stage = Stage.RallypointDelta; break; case "wispgraveyard": stageInfo.stage = Stage.ScorchedAcres; break; case "dampcavesimple": stageInfo.stage = Stage.AbyssalDepths; break; case "shipgraveyard": stageInfo.stage = Stage.SirensCall; break; case "goldshores": stageInfo.stage = Stage.GildedCoast; break; default: stageInfo.stage = Stage.Custom; stageInfo.customStageName = scene.sceneName; break; } return(stageInfo); }
private void ClassicStageInfo_Awake(On.RoR2.ClassicStageInfo.orig_Awake orig, ClassicStageInfo self) { var longTotal = 0UL; var longLongTotal = 0UL; stageSorted.Clear(); totalSorted.Clear(); for (Int32 i = 0; i < hooks.Count; ++i) { var v = hooks[i]; v.Gather(); longTotal += v.stageTime / Main.profilerLongDivisor; longLongTotal += v.longTime / Main.profilerLongDivisor; stageSorted.Add(v); totalSorted.Add(v); if (!history.ContainsKey(v.name)) { history[v.name] = new Histogram(v.name); } history[v.name].AddTime(v.stageTime); } stageSorted.OrderByDescending <ILHookProfile, UInt64>((prof) => prof.stageTime); totalSorted.OrderByDescending <ILHookProfile, UInt64>((prof) => prof.longTime); for (Int32 i = 0; i < Main.numToLog; ++i) { var v = stageSorted[i]; var val = v.stageTime; var perc = (Double)(v.stageTime / Main.profilerLongDivisor) / (Double)longTotal; Main.LogW(v.name + String.Format(":::Time {0}:::Percent {1}", val, perc)); } for (Int32 i = 0; i < Main.numToLog; ++i) { var v = totalSorted[i]; var val = v.longTime; var perc = (Double)(v.longTime / Main.profilerLongDivisor) / (Double)longLongTotal; Main.LogE(v.name + String.Format(":::Time {0}:::Percent {1}", val, perc)); } orig(self); }
private static void ApplyChangesOnStart(On.RoR2.ClassicStageInfo.orig_Start orig, ClassicStageInfo classicStageInfo) { classicStageInfo.PortToNewSystem(); classicStageInfo.ApplyChanges(); orig(classicStageInfo); }
private static StageInfo GetStageInfo(ClassicStageInfo stage) { StageInfo stageInfo = new StageInfo { stage = Stage.Custom, CustomStageName = "", }; var info = stage.GetComponent <SceneInfo>(); if (!info) { return(stageInfo); } var scene = info.sceneDef; if (!scene) { return(stageInfo); } switch (scene.baseSceneName) { case "golemplains": stageInfo.stage = Stage.TitanicPlains; break; case "blackbeach": stageInfo.stage = Stage.DistantRoost; break; case "goolake": stageInfo.stage = Stage.AbandonedAqueduct; break; case "foggyswamp": stageInfo.stage = Stage.WetlandAspect; break; case "frozenwall": stageInfo.stage = Stage.RallypointDelta; break; case "wispgraveyard": stageInfo.stage = Stage.ScorchedAcres; break; case "dampcavesimple": stageInfo.stage = Stage.AbyssalDepths; break; case "shipgraveyard": stageInfo.stage = Stage.SirensCall; break; case "goldshores": stageInfo.stage = Stage.GildedCoast; break; case "arena": stageInfo.stage = Stage.VoidCell; break; case "limbo": stageInfo.stage = Stage.MomentWhole; break; case "skymeadow": stageInfo.stage = Stage.SkyMeadow; break; case "artifactworld": stageInfo.stage = Stage.ArtifactReliquary; break; default: stageInfo.stage = Stage.Custom; stageInfo.CustomStageName = scene.baseSceneName; break; } return(stageInfo); }
private static void OnStageInfoAwake(On.RoR2.ClassicStageInfo.orig_Awake orig, ClassicStageInfo self) { self.ApplyChanges(); orig(self); }