From f52adfe4e0dcbe7192f867df6983e5be9ccb10aa Mon Sep 17 00:00:00 2001 From: Wolfo Date: Tue, 23 Dec 2025 11:47:24 +0100 Subject: [PATCH 01/25] fixes / macros / personal commands ported --- CHANGELOG.md | 46 +++- Code/AutoCompletion/AutoCompleteManager.cs | 16 +- Code/DT-Commands/Buffs.cs | 86 ++++-- Code/DT-Commands/CurrentRun.cs | 43 +++ Code/DT-Commands/Items.cs | 296 ++++++++++++++++++--- Code/DT-Commands/LobbyManagement.cs | 15 +- Code/DT-Commands/Macros.cs | 28 +- Code/DT-Commands/Miscellaneous.cs | 27 ++ Code/DT-Commands/Money.cs | 90 +++++++ Code/DT-Commands/PlayerCommands.cs | 273 ++++++++++++++++++- Code/DT-Commands/Spawners.cs | 26 +- Code/Hooks.cs | 85 +++++- Code/Lang.cs | 54 +++- Code/StringFinder.cs | 74 ++++++ 14 files changed, 1076 insertions(+), 83 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac33cf4..aed4746 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,50 @@ ## Changelog ## - +### 3.22 ### +* **3.22.0** + + * Added commands: + * 'give_drone': Summons drone, specified amount and tier + * 'list_drone', 'list_pickups' + * 'list_mods': Get internal name of all installed mod. + * 'buddhaenemy', 'invulenemy': Buddha mode for all enemies, to make them unkillable. + * 'goto_boss' -> Teleports you to boss, teleporter or boss arenas on stage, so you don't have to fly to Mithrix 100 times in testing. + * 'model': hides model, for screenshotting/recording. + * 'nocooldowns': disables your skill cooldowns + * 'evolve_lemurian': Triggers Artifact of Devotion evolution. + * 'give_voidcoin': Gives Void Markers. + * 'no_interactables': Prevent interactables + + * Added macro/short commands: + * 'dtscanner' -> 100 BoostEquipmentRechrage & Radar Scanner equip for easy map searching. + * 'dtdamage' -> x1000000 damage macro. + * 'random_equip' macro for 'give_equip random' + * 'rich', -> Set money to 2 billion. + * 'poor' -> Set money to 0. + * 'hud': shorthand toggle for 'hud_enable' + * 'skill': shorthand for 'loadout_set_skill_variant self' + * 'unlimited_junk': Toggle for 'junk_unlimited' + * 'cleanse': Alt for 'remove_all_buffs' + + * Updated command functionality: + * Item commands can now grant/remove channeled items + * Item commands now mention you can type 1/2/3 instead of the name type. + * 'spawn_interactable' now also shows interactable names in auto complete. + * 'spawn_interactable' now accepts amount. + * 'spawn_as' now has second argument to permanently spawn as the new body. (Like prior to AC behaviour) //Default False + * 'create_pickup' now supports dropping drones or pickups. + * 'create_pickup' switched {type} and {permanent/temp} argument spots. + * 'give_equip -1' now removes your equipment. + * 'give_buff' now works with negative amount for removing. + * 'true_kill' now bypasses godmode. + * 'loadout_set_skill_variant' now accepts 'self' + * 'random_items' changed default value to not give Lunars & Voids. + + * Amount of spawned interactables/monsters/drones by commands capped at a 100 per command, to not crash the game if you mistype. + * Fixed 'god 0/1'/'buddha 0/1' not setting the toggle's state. + * Fixed 'loadout_set_skin_variant' crashing the game. + ### 3.21 ### - * **3.21.1** * Fixed the cheat ConVars not getting unlocked. * Also enabled the following Alloyed Collective ConVars: `bag_disable_breakout`, `bounce_velocity`, `junk_unlimited` diff --git a/Code/AutoCompletion/AutoCompleteManager.cs b/Code/AutoCompletion/AutoCompleteManager.cs index 2b2e146..8d2e1d1 100644 --- a/Code/AutoCompletion/AutoCompleteManager.cs +++ b/Code/AutoCompletion/AutoCompleteManager.cs @@ -73,7 +73,7 @@ internal static void RegisterAutoCompleteCommands() parser.RegisterStaticVariable("artifact", ArtifactCatalog.artifactDefs.Select(i => $"{(int)i.artifactIndex}|{i.cachedName}|{StringFinder.GetLangInvar(i.nameToken)}"), 1); parser.RegisterStaticVariable("body", BodyCatalog.allBodyPrefabBodyBodyComponents.Select(i => $"{(int)i.bodyIndex}|{i.name}|{StringFinder.GetLangInvar(i.baseNameToken)}"), 1); parser.RegisterStaticVariable("buff", BuffCatalog.buffDefs.Select(i => $"{(int)i.buffIndex}|{StringFinder.GetLangInvar(i.name)}"), 1); - parser.RegisterStaticVariable("droptable", ItemTierCatalog.allItemTierDefs.OrderBy(i => i.tier).Select(i => $"{(int)i.tier}|{i.name}"), 1); + parser.RegisterStaticVariable("tier", ItemTierCatalog.allItemTierDefs.OrderBy(i => i.tier).Select(i => $"{(int)i.tier}|{i.name}"), 1); parser.RegisterStaticVariable("dot", DotController.dotDefs.Select((d, i) => $"{i}|{(DotController.DotIndex)i}"), 1); parser.RegisterStaticVariable("elite", new string[] { "-1|None" }. Concat(EliteCatalog.eliteDefs.Select(i => $"{(int)i.eliteIndex}|{i.name}|{StringFinder.GetLangInvar(i.modifierToken)}")), @@ -81,6 +81,7 @@ internal static void RegisterAutoCompleteCommands() ); parser.RegisterStaticVariable("equip", EquipmentCatalog.equipmentDefs.Select(i => $"{(int)i.equipmentIndex}|{i.name}|{StringFinder.GetLangInvar(i.nameToken)}"), 1); parser.RegisterStaticVariable("item", ItemCatalog.allItemDefs.Select(i => $"{(int)i.itemIndex}|{i.name}|{StringFinder.GetLangInvar(i.nameToken)}"), 1); + parser.RegisterStaticVariable("drone", DroneCatalog.allDroneDefs.Select(i => $"{(int)i.droneIndex}|{i.name}|{StringFinder.GetLangInvar(i.nameToken)}"), 1); parser.RegisterStaticVariable("specific_stage", SceneCatalog.allSceneDefs.Where(i => !i.isOfflineScene).Select(i => $"{(int)i.sceneDefIndex}|{i.cachedName}|{StringFinder.GetLangInvar(i.nameToken)}"), 1); parser.RegisterStaticVariable("team", new string[] { "-1|None" }. Concat(TeamCatalog.teamDefs.Select((t, i) => $"{i}|{(TeamIndex)i}")), @@ -90,9 +91,20 @@ internal static void RegisterAutoCompleteCommands() parser.RegisterStaticVariable("permission_level", CollectEnumNames(typeof(Permissions.Level), typeof(int)), 1); parser.RegisterDynamicVariable("director_card", StringFinder.Instance.DirectorCards, "spawnCard", autocompleteIndex: 1); - parser.RegisterDynamicVariable("interactable", StringFinder.Instance.InteractableSpawnCards, autocompleteIndex: 1); + //parser.RegisterDynamicVariable("interactable", StringFinder.Instance.InteractableSpawnCards, autocompleteIndex: 1); + parser.RegisterDynamicVariable("interactable", StringFinder.Instance.InteractableSpawnCards.Select(i => $"{StringFinder.Instance.InteractableSpawnCards.IndexOf(i)}|{i.name}|{StringFinder.GetLangInvar(i.prefab?.GetComponent()?.GetDisplayName())}"), autocompleteIndex: 1); + parser.RegisterDynamicVariable("player", NetworkUser.instancesList, "userName"); + parser.RegisterStaticVariable("itemTypes", new string[] { + //"0|None", + "1|Permanent", + "2|Temp", + "3|Channelled", + }, + 1 + ); + parser.Scan(System.Reflection.Assembly.GetExecutingAssembly()); } diff --git a/Code/DT-Commands/Buffs.cs b/Code/DT-Commands/Buffs.cs index 36d0d71..7d28ea9 100644 --- a/Code/DT-Commands/Buffs.cs +++ b/Code/DT-Commands/Buffs.cs @@ -88,12 +88,8 @@ private static void CCGiveBuff(ConCommandArgs args) Log.MessageNetworked(String.Format(Lang.PARSE_ERROR, "count", "int"), args, LogLevel.MessageClientOnly); return; } - if (iCount < 0) - { - Log.MessageNetworked(String.Format(Lang.NEGATIVE_ARG, "count"), args, LogLevel.MessageClientOnly); - return; - } - + bool remove = iCount < 0; + float duration = 0f; if (args.Count > 2 && args[2] != Lang.DEFAULT_VALUE && !TextSerialization.TryParseInvariant(args[2], out duration)) { @@ -126,26 +122,46 @@ private static void CCGiveBuff(ConCommandArgs args) var canStack = BuffCatalog.GetBuffDef(buff).canStack; var body = target.body; if (duration == 0f) - { - if (!canStack) + { + if (remove) { - iCount = Math.Min(iCount, 1 - body.GetBuffCount(buff)); + for (int i = 0; i > iCount; i--) + { + body.RemoveBuff(buff); + } } - for (int i = 0; i < iCount; i++) + else { - body.AddBuff(buff); + if (!canStack) + { + iCount = Math.Min(iCount, 1 - body.GetBuffCount(buff)); + } + for (int i = 0; i < iCount; i++) + { + body.AddBuff(buff); + } } - Log.MessageNetworked(string.Format(Lang.GIVEOBJECT, iCount, name, target.name), args); + Log.MessageNetworked(string.Format(Lang.GIVEOBJECT, iCount, name, target.name, ""), args); } else { - if (!canStack) + if (remove) { - iCount = Math.Min(iCount, 1); + for (int i = 0; i > iCount; i--) + { + body.RemoveOldestTimedBuff(buff); + } } - for (int i = 0; i < iCount; i++) + else { - body.AddTimedBuff(buff, duration); + if (!canStack) + { + iCount = Math.Min(iCount, 1); + } + for (int i = 0; i < iCount; i++) + { + body.AddTimedBuff(buff, duration); + } } Log.MessageNetworked($"Gave {iCount} {name} to {target.name} for {duration} seconds", args); } @@ -293,6 +309,44 @@ private static void CCRemoveBuffStacks(ConCommandArgs args) } } + + [ConCommand(commandName = "cleanse", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.REMOVEALLBUFFS_HELP)] + private static void CCCleanse(ConCommandArgs args) + { + if (!Run.instance) + { + Log.MessageNetworked(Lang.NOTINARUN_ERROR, args, LogLevel.MessageClientOnly); + return; + } + bool isDedicatedServer = args.sender == null; + if (isDedicatedServer && (args.Count < 1 || args[0] == Lang.DEFAULT_VALUE)) + { + Log.MessageNetworked(Lang.INSUFFICIENT_ARGS + Lang.REMOVEALLBUFFS_ARGS, args, LogLevel.MessageClientOnly); + return; + } + + + var target = ParseTarget(args, 1); + if (target.failMessage != null) + { + Log.MessageNetworked(target.failMessage, args, LogLevel.MessageClientOnly); + return; + } + + var body = target.body; + if (!body) + { + Log.MessageNetworked(target.failMessage, args, LogLevel.MessageClientOnly); + return; + } + CleanseSystem.CleanseBodyServer(body, true, true, true, true, true, false); + for (int i = 0; i < BuffCatalog.buffCount; i++) + { + body.SetBuffCount((BuffIndex)i, 0); + } + Log.MessageNetworked($"Cleansed {target.name}", args); + } + [ConCommand(commandName = "remove_all_buffs", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.REMOVEALLBUFFS_HELP)] [AutoComplete(Lang.REMOVEALLBUFFS_ARGS)] private static void CCRemoveAllBuffs(ConCommandArgs args) diff --git a/Code/DT-Commands/CurrentRun.cs b/Code/DT-Commands/CurrentRun.cs index d8cf306..662d0ad 100644 --- a/Code/DT-Commands/CurrentRun.cs +++ b/Code/DT-Commands/CurrentRun.cs @@ -13,6 +13,7 @@ public static class CurrentRun { internal static bool noEnemies = false; + internal static bool noInteractables = false; internal static bool lockExp = false; internal static ulong seed; @@ -161,6 +162,40 @@ private static void CCNoEnemies(ConCommandArgs args) Log.MessageNetworked(String.Format(noEnemies ? Lang.SETTING_ENABLED : Lang.SETTING_DISABLED, "no_enemies"), args); } + [ConCommand(commandName = "no_interactables", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.NOINTERACTABLES_HELP)] + [AutoComplete(Lang.ENABLE_ARGS)] + private static void CCNoInteractaböes(ConCommandArgs args) + { + bool enabled = !noInteractables; + if (args.Count > 0) + { + if (!Util.TryParseBool(args[0], out enabled)) + { + Log.MessageNetworked(string.Format(Lang.PARSE_ERROR, "enable", "bool"), args, LogLevel.MessageClientOnly); + return; + } + } + noInteractables = enabled; + if (noInteractables) + { + SceneDirector.onPrePopulateSceneServer += PreventInteractableSpawns; + } + else + { + SceneDirector.onPrePopulateSceneServer -= PreventInteractableSpawns; + } + Log.MessageNetworked(String.Format(noInteractables ? Lang.SETTING_ENABLED : Lang.SETTING_DISABLED, "no_interactables"), args); + } + + private static void PreventInteractableSpawns(SceneDirector obj) + { + if (noInteractables) + { + obj.interactableCredit = 0; + //obj.teleporterSpawnCard = null; + } + } + [ConCommand(commandName = "lock_exp", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.LOCKEXP_HELP)] [AutoComplete(Lang.ENABLE_ARGS)] private static void CCLockExperience(ConCommandArgs args) @@ -681,6 +716,14 @@ private static void CCSetTime(ConCommandArgs args) Run.instance.SetRunStopwatch(setTime); Log.MessageNetworked("Run timer set to " + setTime, args); } + + + [ConCommand(commandName = "evolve_lemurian", flags = ConVarFlags.ExecuteOnServer, helpText = "Evolves all Devoted Lemurians")] + [ConCommand(commandName = "evolve_lemurians", flags = ConVarFlags.ExecuteOnServer, helpText = "Evolves all Devoted Lemurians")] + public static void CC_evolve_lemurian(ConCommandArgs args) + { + DevotionInventoryController.ActivateAllDevotedEvolution(); + } } // ReSharper disable once ClassNeverInstantiated.Global diff --git a/Code/DT-Commands/Items.cs b/Code/DT-Commands/Items.cs index 7f85621..1101dbb 100644 --- a/Code/DT-Commands/Items.cs +++ b/Code/DT-Commands/Items.cs @@ -8,6 +8,7 @@ using UnityEngine.Networking; using static DebugToolkit.Log; using static DebugToolkit.Util; +using static Rewired.InputMapper; namespace DebugToolkit.Commands { @@ -68,6 +69,43 @@ private static void CCListEquip(ConCommandArgs args) Log.MessageNetworked(s, args, LogLevel.MessageClientOnly); } + [ConCommand(commandName = "list_drone", flags = ConVarFlags.None, helpText = Lang.LISTDRONE_HELP)] + [AutoComplete(Lang.LISTQUERY_ARGS)] + private static void CCListDrone(ConCommandArgs args) + { + var sb = new StringBuilder(); + var arg = args.Count > 0 ? args[0] : ""; + var indices = StringFinder.Instance.GetDronesFromPartial(arg); + foreach (var index in indices) + { + var definition = DroneCatalog.GetDroneDef(index); + var realName = Language.currentLanguage.GetLocalizedStringByToken(definition.nameToken); + bool enabled = Run.instance && Run.instance.IsDroneAvailable(index); + sb.AppendLine($"[{(int)index}]{definition.name} \"{realName}\" (enabled={enabled})"); + } + var s = sb.Length > 0 ? sb.ToString().TrimEnd('\n') : string.Format(Lang.NOMATCH_ERROR, "drone", arg); + Log.MessageNetworked(s, args, LogLevel.MessageClientOnly); + } + + [ConCommand(commandName = "list_pickups", flags = ConVarFlags.None, helpText = Lang.LISTDRONE_HELP)] + [AutoComplete(Lang.LISTQUERY_ARGS)] + private static void CCListPickup(ConCommandArgs args) + { + var sb = new StringBuilder(); + var arg = args.Count > 0 ? args[0] : ""; + var indices = StringFinder.Instance.GetPickupsFromPartial(arg); + foreach (var index in indices) + { + var definition = PickupCatalog.GetPickupDef(index); + var realName = Language.currentLanguage.GetLocalizedStringByToken(definition.nameToken); + bool enabled = Run.instance && Run.instance.IsPickupAvailable(index); + sb.AppendLine($"[{index.value}]{definition.internalName} \"{realName}\" (enabled={enabled})"); + } + var s = sb.Length > 0 ? sb.ToString().TrimEnd('\n') : string.Format(Lang.NOMATCH_ERROR, "pickups", arg); + Log.MessageNetworked(s, args, LogLevel.MessageClientOnly); + } + + [ConCommand(commandName = "dump_inventories", flags = ConVarFlags.None, helpText = Lang.DUMPINVENTORIES_HELP)] private static void CCDumpInventories(ConCommandArgs args) { @@ -138,7 +176,7 @@ private static void CCGiveItem(ConCommandArgs args) } var type = ParseItemType(args, 2); - if (type == ItemType.None) + if (type <= ItemType.None || type >= ItemType.Count) { Log.MessageNetworked(String.Format(Lang.INVALID_ARG_VALUE, "type"), args, LogLevel.MessageClientOnly); return; @@ -169,13 +207,13 @@ private static void CCGiveItem(ConCommandArgs args) return; } GiveItem(inventory, item, amount, type); - Log.MessageNetworked(string.Format(Lang.GIVEOBJECT, amount, name, target.name), args); + Log.MessageNetworked(string.Format(Lang.GIVEOBJECT, amount, name, target.name, type), args); } else if (amount < 0) { amount = Math.Min(-amount, GetItemCount(inventory, item, type)); RemoveItem(inventory, item, amount, type); - Log.MessageNetworked(string.Format(Lang.REMOVEOBJECT, amount, name, target.name), args); + Log.MessageNetworked(string.Format(Lang.REMOVEOBJECT, amount, name, target.name, type), args); } else { @@ -187,9 +225,104 @@ private static void CCGiveItem(ConCommandArgs args) } } + [ConCommand(commandName = "give_drone", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.GIVEDRONE_HELP)] + [AutoComplete(Lang.GIVEDRONE_ARGS)] + private static void CCGiveDrone(ConCommandArgs args) + { + //give_drone {name} {amount} {tier} + if (!Run.instance) + { + Log.MessageNetworked(Lang.NOTINARUN_ERROR, args, LogLevel.MessageClientOnly); + return; + } + bool isDedicatedServer = args.sender == null; + if (args.Count == 0 || (isDedicatedServer && (args.Count < 4 || args[3] == Lang.DEFAULT_VALUE))) + { + Log.MessageNetworked(Lang.INSUFFICIENT_ARGS + Lang.GIVEITEM_ARGS, args, LogLevel.MessageClientOnly); + return; + } + + int amount = 1; + if (args.Count > 1 && args[1] != Lang.DEFAULT_VALUE && !TextSerialization.TryParseInvariant(args[1], out amount)) + { + Log.MessageNetworked(String.Format(Lang.PARSE_ERROR, "count", "int"), args, LogLevel.MessageClientOnly); + return; + } + int tier = 1; + if (args.Count > 2 && args[2] != Lang.DEFAULT_VALUE && !TextSerialization.TryParseInvariant(args[2], out tier)) + { + Log.MessageNetworked(String.Format(Lang.PARSE_ERROR, "tier", "int"), args, LogLevel.MessageClientOnly); + return; + } + + var target = Buffs.ParseTarget(args, 3); + if (target.failMessage != null) + { + Log.MessageNetworked(target.failMessage, args, LogLevel.MessageClientOnly); + return; + } + if (!target.body) + { + Log.MessageNetworked("No target body found", args, LogLevel.MessageClientOnly); + return; + } + + var drone = StringFinder.Instance.GetDroneFromPartial(args[0]); + if (drone == DroneIndex.None) + { + Log.MessageNetworked(string.Format(Lang.OBJECT_NOTFOUND, "drone", args[0]), args, LogLevel.MessageClientOnly); + return; + } + DroneDef droneDef = DroneCatalog.GetDroneDef(drone); + + if (droneDef == null) + { + Log.MessageNetworked(string.Format(Lang.OBJECT_NOTFOUND, "drone", args[0]), args, LogLevel.MessageClientOnly); + return; + } + if (Run.instance.IsDroneExpansionLocked(drone)) + { + Log.MessageNetworked(string.Format(Lang.EXPANSION_LOCKED, "drone", Util.GetExpansion(droneDef.requiredExpansion)), args, LogLevel.MessageClientOnly); + return; + } + if (amount > 50) + { + amount = 50; + Log.MessageNetworked($"Limited to 50, please don't spawn too many things at once.", args, LogLevel.MessageClientOnly); + } + if (amount > 0) + { + for (int i = 0; i < amount; i++) + { + CharacterMaster newlySpawnedDrone = new MasterSummon + { + masterPrefab = droneDef.masterPrefab, + position = target.body.transform.position, + rotation = target.body.transform.rotation, + summonerBodyObject = target.body.gameObject, + ignoreTeamMemberLimit = true, + useAmbientLevel = true, + enablePrintController = true + }.Perform(); + if (tier > 1) + { + newlySpawnedDrone.inventory.GiveItemPermanent(DLC3Content.Items.DroneUpgradeHidden, (tier - 1)); + } + } + var name = droneDef.name; + Log.MessageNetworked(string.Format(Lang.GIVEDRONE, amount, name, target.name, tier), args); + } + else + { + Log.MessageNetworked("Nothing happened", args); + } + + } + + [ConCommand(commandName = "random_items", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.RANDOMITEM_HELP)] [AutoComplete(Lang.RANDOMITEM_ARGS)] - private static void CCRandomItems(ConCommandArgs args) + private static void CCRandomItemsTiered(ConCommandArgs args) { if (!Run.instance) { @@ -216,7 +349,7 @@ private static void CCRandomItems(ConCommandArgs args) } var type = ParseItemType(args, 2); - if (type == ItemType.None) + if (type <= ItemType.None || type >= ItemType.Count) { Log.MessageNetworked(String.Format(Lang.INVALID_ARG_VALUE, "type"), args, LogLevel.MessageClientOnly); return; @@ -285,6 +418,12 @@ private static void CCGiveEquipment(ConCommandArgs args) inventory.GiveRandomEquipment(); equip = inventory.GetEquipmentIndex(); } + else if (args[0] == "-1") + { + inventory.SetEquipmentIndex(EquipmentIndex.None, true); + Log.MessageNetworked($"Removed current Equipment from {target.name}", args); + return; + } else { equip = StringFinder.Instance.GetEquipFromPartial(args[0]); @@ -305,6 +444,14 @@ private static void CCGiveEquipment(ConCommandArgs args) Log.MessageNetworked($"Gave {name} to {target.name}", args); } + [ConCommand(commandName = "random_equip", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.RANDOMEQUIP_HELP)] + [AutoComplete(Lang.RANDOMEQUIP_ARGS)] + private static void CCGiveRandomEquipment(ConCommandArgs args) + { + DebugToolkit.InvokeCMD(args.sender, "give_equip", "RANDOM"); + } + + [ConCommand(commandName = "create_pickup", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.CREATEPICKUP_HELP)] [AutoComplete(Lang.CREATEPICKUP_ARGS)] private static void CCCreatePickup(ConCommandArgs args) @@ -337,25 +484,38 @@ private static void CCCreatePickup(ConCommandArgs args) return; } - var type = ParseItemType(args, 1); - if (type == ItemType.None) + ItemType type = ItemType.Permanent; + if (args.Count > 2 && args[2] != Lang.DEFAULT_VALUE) { - Log.MessageNetworked(String.Format(Lang.INVALID_ARG_VALUE, "type"), args, LogLevel.MessageClientOnly); - return; + type = ParseItemType(args, 2); + if (type <= ItemType.None || type >= ItemType.Count) + { + Log.MessageNetworked(String.Format(Lang.INVALID_ARG_VALUE, "type"), args, LogLevel.MessageClientOnly); + return; + } } - bool searchEquip = true, searchItem = true; - if (args.Count > 2 && args[2] != Lang.DEFAULT_VALUE) + bool searchEquip = true, searchItem = true, searchDrone = true, skip = false; + if (args.Count > 1 && args[1] != Lang.DEFAULT_VALUE) { - switch (args[2].ToUpperInvariant()) + switch (args[1].ToUpperInvariant()) { - case Lang.BOTH: + case Lang.ALL: + break; + case Lang.PICKUP: + skip = true; break; case Lang.ITEM: searchEquip = false; + searchDrone = false; break; case Lang.EQUIP: searchItem = false; + searchDrone = false; + break; + case Lang.DRONE: + searchItem = false; + searchEquip = false; break; default: Log.MessageNetworked(String.Format(Lang.INVALID_ARG_VALUE, "search"), args, LogLevel.MessageClientOnly); @@ -363,6 +523,7 @@ private static void CCCreatePickup(ConCommandArgs args) } } PickupIndex final = PickupIndex.none; + DroneIndex drone = DroneIndex.None; EquipmentIndex equipment = EquipmentIndex.None; ItemIndex item = ItemIndex.None; @@ -375,31 +536,76 @@ private static void CCCreatePickup(ConCommandArgs args) final = PickupCatalog.FindPickupIndex("MiscPickupIndex.VoidCoin"); break; default: - if (searchEquip) - { - equipment = StringFinder.Instance.GetEquipFromPartial(args[0]); - } - if (searchItem) + if (skip) { - item = StringFinder.Instance.GetItemFromPartial(args[0]); - } - if (item == ItemIndex.None && equipment == EquipmentIndex.None) - { - Log.MessageNetworked(Lang.CREATEPICKUP_NOTFOUND, args, LogLevel.MessageClientOnly); - return; - } - else if (item != ItemIndex.None && equipment != EquipmentIndex.None) - { - Log.MessageNetworked(string.Format(Lang.CREATEPICKUP_AMBIGIOUS_2, item, equipment), args, LogLevel.MessageClientOnly); - return; - } - else if (equipment != EquipmentIndex.None) - { - final = PickupCatalog.FindPickupIndex(equipment); + int? pickup2 = args.TryGetArgInt(0); + if (pickup2 != null) + { + final.value = (int)pickup2; + } + else + { + final = StringFinder.Instance.GetPickupFromPartial(args[0]); + } } else - { - final = PickupCatalog.FindPickupIndex(item); + { + if (searchEquip) + { + equipment = StringFinder.Instance.GetEquipFromPartial(args[0]); + } + if (searchItem) + { + item = StringFinder.Instance.GetItemFromPartial(args[0]); + } + if (searchDrone) + { + drone = StringFinder.Instance.GetDroneFromPartial(args[0]); + } + if (item == ItemIndex.None && equipment == EquipmentIndex.None && drone == DroneIndex.None) + { + Log.MessageNetworked(Lang.CREATEPICKUP_NOTFOUND, args, LogLevel.MessageClientOnly); + return; + } + else if(item != ItemIndex.None && equipment != EquipmentIndex.None|| + drone != DroneIndex.None && equipment != EquipmentIndex.None || + item != ItemIndex.None && drone != DroneIndex.None ) + { + var def1 = ItemCatalog.GetItemDef(item); + var def2 = EquipmentCatalog.GetEquipmentDef(equipment); + var def3 = DroneCatalog.GetDroneDef(drone); + string foundResults = string.Empty; + if (def1) + { + foundResults += $"{item}|{def1.name}|{Language.GetString(def1.nameToken)}"; + } + if (def2) + { + foundResults += $"{equipment}|{def2.name}|{Language.GetString(def2.nameToken)}"; + } + if (def3) + { + foundResults += $"{drone}|{def3.name}|{Language.GetString(def3.nameToken)}"; + } + Log.MessageNetworked(string.Format(Lang.CREATEPICKUP_AMBIGIOUS_4, foundResults), args, LogLevel.MessageClientOnly); + return; + } + else if (equipment != EquipmentIndex.None) + { + final = PickupCatalog.FindPickupIndex(equipment); + } + else if (drone != DroneIndex.None) + { + final = PickupCatalog.FindPickupIndex(drone); + } + else if (item != ItemIndex.None) + { + final = PickupCatalog.FindPickupIndex(item); + } + else + { + final.value = args.TryGetArgInt(0).GetValueOrDefault(-1); + } } break; } @@ -411,6 +617,7 @@ private static void CCCreatePickup(ConCommandArgs args) { pickupIndex = final, decayValue = type == ItemType.Temp ? 1f : 0f, + //upgradeValue }, }, body.transform.position, body.inputBank.aimDirection * 30f); } @@ -648,6 +855,8 @@ internal enum ItemType None, Permanent, Temp, + Channeled, + Count, } private static int GetItemCount(Inventory inventory, ItemIndex itemIndex, ItemType type) @@ -658,6 +867,8 @@ private static int GetItemCount(Inventory inventory, ItemIndex itemIndex, ItemTy return inventory.GetItemCountPermanent(itemIndex); case ItemType.Temp: return inventory.GetItemCountTemp(itemIndex); + case ItemType.Channeled: + return inventory.GetItemCountChanneled(itemIndex); default: Log.Message(Lang.NOMESSAGE, LogLevel.Warning); return 0; @@ -674,6 +885,9 @@ private static void GiveItem(Inventory inventory, ItemIndex itemIndex, int count case ItemType.Temp: inventory.GiveItemTemp(itemIndex, count); break; + case ItemType.Channeled: + inventory.GiveItemChanneled(itemIndex, count); + break; default: Log.Message(Lang.NOMESSAGE, LogLevel.Warning); break; @@ -690,6 +904,9 @@ private static void RemoveItem(Inventory inventory, ItemIndex itemIndex, int cou case ItemType.Temp: inventory.RemoveItemTemp(itemIndex, count); break; + case ItemType.Channeled: + inventory.RemoveItemChanneled(itemIndex, count); + break; default: Log.Message(Lang.NOMESSAGE, LogLevel.Warning); break; @@ -825,6 +1042,13 @@ private static BasicPickupDropTable ParseDroptable(ConCommandArgs args, int inde droptable.selector.Clear(); droptable.canDropBeReplaced = canDropBeReplaced; if (args.Count < index + 1 || args[index] == Lang.DEFAULT_VALUE || args[index].ToUpperInvariant() == Lang.ALL) + { + droptable.Add(availableDropLists[ItemTier.Tier1], 1f); + droptable.Add(availableDropLists[ItemTier.Tier2], 1f); + droptable.Add(availableDropLists[ItemTier.Tier3], 1f); + droptable.Add(availableDropLists[ItemTier.Boss], 1f); + } + else if (args[index].ToUpperInvariant() == Lang.ALL) { foreach (var itemTier in StringFinder.Instance.GetItemTiersFromPartial("")) { @@ -947,5 +1171,7 @@ private static DevotionInventoryController GetDevotionController(CharacterMaster } return controller; } + + } } diff --git a/Code/DT-Commands/LobbyManagement.cs b/Code/DT-Commands/LobbyManagement.cs index bd29c65..edc4894 100644 --- a/Code/DT-Commands/LobbyManagement.cs +++ b/Code/DT-Commands/LobbyManagement.cs @@ -66,10 +66,23 @@ private static void CCTrueKill(ConCommandArgs args) } master = player.master; } - + master.godMode = false; + master.UpdateBodyGodMode(); master.TrueKill(); Log.MessageNetworked(master.name + " was killed by server.", args); } + [ConCommand(commandName = "true_kill_all", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.TRUEKILL_HELP)] + private static void CCTrueKillAll(ConCommandArgs args) + { + foreach (var player in PlayerCharacterMasterController.instances) + { + player.master.godMode = false; + player.master.UpdateBodyGodMode(); + player.master.TrueKill(); + + } + Log.MessageNetworked("Everyone was killed by server.", args); + } private static NetworkConnection GetClientFromArgs(ConCommandArgs args) { diff --git a/Code/DT-Commands/Macros.cs b/Code/DT-Commands/Macros.cs index 7d0209c..e1e3d4d 100644 --- a/Code/DT-Commands/Macros.cs +++ b/Code/DT-Commands/Macros.cs @@ -1,4 +1,5 @@ using RoR2; +using UnityEngine.Networking; namespace DebugToolkit.Commands { @@ -43,7 +44,32 @@ private static void Zoom(ConCommandArgs args) Invoke(args.sender, "give_item", "feather", "200"); } - private static void Invoke(NetworkUser user, string commandname, params string[] args) + [ConCommand(commandName = "dtdamage", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.MACRO_DTDAMAGE_HELP)] + private static void Damage(ConCommandArgs args) + { + Invoke(args.sender, "give_item", "boostdamage", "9999990"); + } + + [ConCommand(commandName = "scanner", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.MACRO_SCANNER_HELP)] + [ConCommand(commandName = "dtscanner", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.MACRO_SCANNER_HELP)] + public static void CCScanner(ConCommandArgs args) + { + if (!args.senderMaster) + { + return; + } + if (!NetworkServer.active) + { + return; + } + Invoke(args.sender, "give_item", "BoostEquipmentRecharge", "100"); + Invoke(args.sender, "give_equip", "Scanner"); + //args.senderMaster.inventory.SetEquipmentIndex(RoR2Content.Equipment.Scanner.equipmentIndex, false); + //args.senderMaster.inventory.GiveItemPermanent(RoR2Content.Items.BoostEquipmentRecharge, 100); + } + + + public static void Invoke(NetworkUser user, string commandname, params string[] args) { DebugToolkit.InvokeCMD(user, commandname, args); } diff --git a/Code/DT-Commands/Miscellaneous.cs b/Code/DT-Commands/Miscellaneous.cs index 139a648..ad78805 100644 --- a/Code/DT-Commands/Miscellaneous.cs +++ b/Code/DT-Commands/Miscellaneous.cs @@ -79,5 +79,32 @@ static IEnumerator InvokeRoutine(System.Action action, float delay) action(); } } + + + [ConCommand(commandName = "list_mods", flags = ConVarFlags.None, helpText = "List installed mod names to get them for compatibility." + Lang.LISTMODS_ARGS)] + [AutoComplete(Lang.LISTMODS_ARGS)] + public static void CCMods(ConCommandArgs args) + { + bool requiredByAll = args.TryGetArgBool(0).GetValueOrDefault(false); + string log = string.Empty; + if (requiredByAll) + { + log = "All RequiredByAllTaggedMods\n\n"; + foreach (var a in NetworkModCompatibilityHelper._networkModList) + { + log += a.ToString() + "\n"; + } + } + else + { + log = "All loaded mods\n\n"; + foreach (var a in BepInEx.Bootstrap.Chainloader.PluginInfos) + { + log += a.ToString() + "\n"; + } + } + Debug.Log(log); + } + } } diff --git a/Code/DT-Commands/Money.cs b/Code/DT-Commands/Money.cs index 34a0842..61e0e2c 100644 --- a/Code/DT-Commands/Money.cs +++ b/Code/DT-Commands/Money.cs @@ -10,6 +10,7 @@ namespace DebugToolkit.Commands class Money { [ConCommand(commandName = "give_lunar", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.GIVELUNAR_HELP)] + [ConCommand(commandName = "give_lunarcoin", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.GIVELUNAR_HELP)] [AutoComplete(Lang.GIVELUNAR_ARGS)] private static void CCGiveLunar(ConCommandArgs args) { @@ -45,6 +46,48 @@ private static void CCGiveLunar(ConCommandArgs args) Log.MessageNetworked(str, args); } + [ConCommand(commandName = "give_void", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.GIVEVOID_HELP)] + [ConCommand(commandName = "give_voidcoin", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.GIVEVOID_HELP)] + [AutoComplete(Lang.GIVELUNAR_ARGS)] + private static void CCGiveVoidCoin(ConCommandArgs args) + { + if (!Run.instance) + { + Log.MessageNetworked(Lang.NOTINARUN_ERROR, args, LogLevel.MessageClientOnly); + return; + } + if (args.sender == null) + { + Log.Message("Can't modify Lunar coins of other users directly.", LogLevel.MessageClientOnly); + return; + } + int amount = 1; + if (args.Count > 0 && args[0] != Lang.DEFAULT_VALUE && !TextSerialization.TryParseInvariant(args[0], out amount)) + { + Log.MessageNetworked(String.Format(Lang.PARSE_ERROR, "amount", "int"), args, LogLevel.MessageClientOnly); + return; + } + string str = "Nothing happened. Big surprise."; + CharacterMaster master = args.senderMaster; + if (!master) + { + Log.MessageNetworked("No master to send coins to",args, LogLevel.MessageClientOnly); + return; + } + if (amount > 0) + { + master.GiveVoidCoins((uint)amount); + str = string.Format(Lang.GIVEVOIDC_2, "Gave", amount); + } + if (amount < 0) + { + master.GiveVoidCoins((uint)(amount)); + str = string.Format(Lang.GIVEVOIDC_2, "Removed", amount); + } + Log.MessageNetworked(str, args); + } + + [ConCommand(commandName = "give_money", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.GIVEMONEY_HELP)] [AutoComplete(Lang.GIVEMONEY_ARGS)] private static void CCGiveMoney(ConCommandArgs args) @@ -97,6 +140,53 @@ private static void CCGiveMoney(ConCommandArgs args) Log.MessageNetworked("$$$", args); } + [ConCommand(commandName = "rich", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.ALLMONEY_HELP)] + [ConCommand(commandName = "poor", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.NO_MONEY_HELP)] + [AutoComplete(Lang.MONEY_ARGS)] + public static void CC_poor(ConCommandArgs args) + { + bool rich = args.commandName == "rich"; + if (args.Count > 0 && args[0].ToUpperInvariant() != Lang.ALL && args[0].ToUpperInvariant() != Lang.DEFAULT_VALUE) + { + NetworkUser player = Util.GetNetUserFromString(args.userArgs, 1); + if (player != null) + { + if (rich) + { + player.master.GiveMoney(2000000000 - player.master.money); + Log.MessageNetworked("$$$", args); + } + else + { + player.master.money = 0; + Log.MessageNetworked("-$", args); + } + } + else + { + Log.MessageNetworked(Lang.PLAYER_NOTFOUND, args, LogLevel.MessageClientOnly); + return; + } + } + else + { + foreach (PlayerCharacterMasterController player in PlayerCharacterMasterController.instances) + { + if (rich) + { + player.master.GiveMoney(2000000000 - player.master.money); + Log.MessageNetworked("We're rich", args); + } + else + { + player.master.money = 0; + Log.MessageNetworked("We're poor", args); + } + } + } + } + + private static void GiveMasterMoney(CharacterMaster master, int amount) { if (amount > 0) diff --git a/Code/DT-Commands/PlayerCommands.cs b/Code/DT-Commands/PlayerCommands.cs index 1ce61ef..b831235 100644 --- a/Code/DT-Commands/PlayerCommands.cs +++ b/Code/DT-Commands/PlayerCommands.cs @@ -1,8 +1,13 @@ +using HG; using RoR2; +using RoR2.ContentManagement; using RoR2.ExpansionManagement; using System; using System.Collections.Generic; +using System.Security.Cryptography; using UnityEngine; +using UnityEngine.Networking; +using UnityEngine.SocialPlatforms; using static DebugToolkit.Log; namespace DebugToolkit.Commands @@ -21,6 +26,7 @@ private static void CCGodModeToggle(ConCommandArgs args) Log.MessageNetworked(string.Format(Lang.PARSE_ERROR, "enable", "bool"), args, LogLevel.MessageClientOnly); return; } + Hooks.god = modeOn; } else { @@ -49,14 +55,74 @@ private static void CCBuddhaModeToggle(ConCommandArgs args) Log.MessageNetworked(string.Format(Lang.PARSE_ERROR, "enable", "bool"), args, LogLevel.MessageClientOnly); return; } + Hooks.buddha = modeOn; } else { modeOn = Hooks.ToggleBuddha(); } + foreach (var player in PlayerCharacterMasterController.instances) + { + var body = player.master.GetBody(); + if (body != null) + { + if (modeOn) + { + body.bodyFlags |= CharacterBody.BodyFlags.Buddha; + } + else + { + body.bodyFlags &= ~CharacterBody.BodyFlags.Buddha; + } + } + } + + Log.MessageNetworked(String.Format(modeOn ? Lang.SETTING_ENABLED : Lang.SETTING_DISABLED, "Buddha mode"), args); } + [ConCommand(commandName = "buddhaenemy", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.BUDDHA_HELP2)] + [ConCommand(commandName = "budaenemy", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.BUDDHA_HELP2)] + [ConCommand(commandName = "invulenemy", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.BUDDHA_HELP2)] + [AutoComplete(Lang.ENABLE_ARGS)] + private static void CCBuddhaMONSTERModeToggle(ConCommandArgs args) + { + bool modeOn; + if (args.Count > 0) + { + if (!Util.TryParseBool(args[0], out modeOn)) + { + Log.MessageNetworked(string.Format(Lang.PARSE_ERROR, "enable", "bool"), args, LogLevel.MessageClientOnly); + return; + } + Hooks.buddhaMonsters = modeOn; + } + else + { + Hooks.buddhaMonsters = !Hooks.buddhaMonsters; + modeOn = Hooks.buddhaMonsters; + } + foreach (var body in CharacterBody.instancesList) + { + if (body && !body.isPlayerControlled) + { + if (modeOn) + { + body.bodyFlags |= RoR2.CharacterBody.BodyFlags.Buddha; + } + else + { + body.bodyFlags &= ~RoR2.CharacterBody.BodyFlags.Buddha; + } + } + } + + + Log.MessageNetworked(String.Format(modeOn ? Lang.SETTING_ENABLED : Lang.SETTING_DISABLED, "Monster Buddha mode"), args); + } + + + [ConCommand(commandName = "noclip", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.NOCLIP_HELP)] [AutoComplete(Lang.ENABLE_ARGS)] private static void CCNoclip(ConCommandArgs args) @@ -107,6 +173,81 @@ private static void CCCursorTeleport(ConCommandArgs args) TeleportNet.Invoke(args.sender); // callback } + + [ConCommand(commandName = "goto_boss", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.CURSORTELEPORT_HELP)] + private static void CCGoto_Boss(ConCommandArgs args) + { + string stage = Stage.instance.sceneDef.cachedName; + Component senderBody = args.GetSenderBody(); + Vector3 newPosition = Vector3.zero; + string destination = string.Empty; + + if (TeleporterInteraction.instance) + { + destination = "Teleporter"; + newPosition = TeleporterInteraction.instance.transform.position; + newPosition += new Vector3(0, 1, 0); + } + else if (BossGroup.GetTotalBossCount() > 0) + { + for (int i = 0; i < CharacterBody.instancesList.Count; i++) + { + if (CharacterBody.instancesList[i].isBoss) + { + newPosition = CharacterBody.instancesList[i].corePosition; + destination = CharacterBody.instancesList[i].name; + break; + } + } + } + else if (stage == "moon2") + { + newPosition = new Vector3(-11, 490, 80); + destination = "Mithrix Arena"; + } + else if (stage == "solutionalhaunt") + { + newPosition = new Vector3(252.5426f, -549.5432f, -90.2127f); //Cutscene Trigger + destination = "Solus Wing Hallway"; + GameObject cutsceneTrigger = GameObject.Find("/HOLDER2: Mission and Meta-Related Systems/Cutscene/Trigger Hallway Trap"); + cutsceneTrigger.GetComponent().Triggered = true; //Because it's OnExitTrigger, can't just teleport there + } + else if (stage == "meridian") + { + newPosition = new Vector3(85.2065f, 146.5167f, -70.5265f); //Cutscene Trigger + destination = "False Son Arena"; + } + else if (stage == "mysteryspace") + { + newPosition = new Vector3(362.9097f, -151.5964f, 213.0157f); //Obelisk + destination = "Obelisk"; + } + else if (stage == "voidraid") + { + destination = "Voidling Arena"; + newPosition = new Vector3(-105f, 0.2f, 92f); + } + if (stage == "conduitcanyon") + { + //Auto complete the power pedestals + List instancesList = InstanceTracker.GetInstancesList(); + foreach (PowerPedestal powerPedestal in instancesList) + { + powerPedestal.SetComplete(true); + } + Debug.Log("Autocompleting Sentry Terminals"); + } + if (newPosition == Vector3.zero) + { + Debug.Log("No Teleporter, Specific Location or Boss Monster found."); + return; + } + TeleportHelper.TeleportGameObject(senderBody.gameObject, newPosition); + Debug.Log($"Teleported you to {destination}"); + + } + + [ConCommand(commandName = "spawn_as", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.SPAWNAS_HELP)] [AutoComplete(Lang.SPAWNAS_ARGS)] private static void CCSpawnAs(ConCommandArgs args) @@ -116,7 +257,7 @@ private static void CCSpawnAs(ConCommandArgs args) Log.MessageNetworked(Lang.NOTINARUN_ERROR, args, LogLevel.MessageClientOnly); return; } - if (args.Count == 0 || (args.sender == null && (args.Count < 2 || args[1] == Lang.DEFAULT_VALUE))) + if (args.Count == 0 || (args.sender == null && (args.Count < 3 || args[2] == Lang.DEFAULT_VALUE))) { Log.MessageNetworked(Lang.INSUFFICIENT_ARGS + Lang.SPAWNAS_ARGS, args, LogLevel.MessageClientOnly); return; @@ -131,7 +272,7 @@ private static void CCSpawnAs(ConCommandArgs args) GameObject newBody = BodyCatalog.GetBodyPrefab(bodyIndex); CharacterMaster master = args.senderMaster; - if (args.Count > 1 && args[1] != Lang.DEFAULT_VALUE) + if (args.Count > 2 && args[2] != Lang.DEFAULT_VALUE) { NetworkUser player = Util.GetNetUserFromString(args.userArgs, 1); if (player == null) @@ -150,7 +291,15 @@ private static void CCSpawnAs(ConCommandArgs args) } master.bodyPrefab = newBody; - Log.MessageNetworked(args.sender.userName + " is spawning as " + newBody.name, args); + if (args.TryGetArgBool(1).GetValueOrDefault(false)) + { + master.originalBodyPrefab = newBody; + Log.MessageNetworked(args.sender.userName + " is spawning as " + newBody.name + " for the rest of the run.", args); + } + else + { + Log.MessageNetworked(args.sender.userName + " is spawning as " + newBody.name + " for the current stage.", args); + } if (!master.GetBody()) { @@ -506,7 +655,8 @@ private static void GatherObjectState(System.Text.StringBuilder sb, Component co sb.AppendLine($"{esm.customName} state: {esm.state?.ToString() ?? string.Empty}"); } } - + + //Apply_Skin is probably better, but does not save loadout [ConCommand(commandName = "loadout_set_skin_variant", flags = ConVarFlags.None, helpText = Lang.LOADOUTSKIN_HELP)] [AutoComplete(Lang.LOADOUTSKIN_ARGS)] public static void CCLoadoutSetSkinVariant(ConCommandArgs args) @@ -576,7 +726,7 @@ public static void CCLoadoutSetSkinVariant(ConCommandArgs args) var modelSkinController = args.senderBody.modelLocator.modelTransform.GetComponent(); if (modelSkinController) { - modelSkinController.ApplySkin(requestedSkinIndexChange); + modelSkinController.StartCoroutine(modelSkinController.ApplySkinAsync(requestedSkinIndexChange, AsyncReferenceHandleUnloadType.OnSceneUnload)); } } } @@ -605,5 +755,118 @@ internal static bool UpdateCurrentPlayerBody(out NetworkUser networkUser, out Ch return false; } + + + + //loadout_set_skill_variant self <- adding cuz requested //Does not work + //[ConCommand(commandName = "loadout_set_skill_variant self", flags = ConVarFlags.ExecuteOnServer, helpText = "Switch Skills of current survivor Shorthand")] + [ConCommand(commandName = "skill", flags = ConVarFlags.ExecuteOnServer, helpText = "[skill_slot] [skill_variant]\nSets the skill variant for the sender's user profile.")] + public static void CC_Skill(ConCommandArgs args) + { + if (!args.sender) + { + Log.Message("Can't choose self if not in-game!", LogLevel.Error); + return; + } + if (args.Count < 2) + { + Log.MessageNetworked(Lang.INSUFFICIENT_ARGS + Lang.LOADOUTSKIN_ARGS, args, LogLevel.MessageClientOnly); + return; + } + BodyIndex argBodyIndex = BodyIndex.None; + if (args.senderBody) + { + argBodyIndex = args.senderBody.bodyIndex; + } + else + { + if (args.senderMaster && args.senderMaster.bodyPrefab) + { + argBodyIndex = args.senderMaster.bodyPrefab.GetComponent().bodyIndex; + } + else + { + argBodyIndex = args.sender.bodyIndexPreference; + } + } + args.userArgs = new List + { + argBodyIndex.ToString(), + args[0], + args[1], + }; + UserProfile.CCLoadoutSetSkillVariant(args); + + + } + + + + [ConCommand(commandName = "unlimited_junk", flags = ConVarFlags.ExecuteOnServer, helpText = "Toggle junk_unlimited. Makes skillchecks ingore junk cost.")] + public static void CC_JunkAlt(ConCommandArgs args) + { + JunkController.junkUnlimited.value = !JunkController.junkUnlimited.value; + if (JunkController.junkUnlimited.value) + { + Macros.Invoke(args.sender, "give_item", ((int)DLC3Content.Items.Junk.itemIndex).ToString(), "12"); + //Junk unlimited doesn't actually bypass the check. + //It just makes it not remove junk + } + Log.MessageNetworked(String.Format(JunkController.junkUnlimited.value ? Lang.SETTING_ENABLED : Lang.SETTING_DISABLED, "Unlimtied Junk"), args); + + } + + + public static bool NoCooldowns = false; + + [ConCommand(commandName = "nocooldown", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.LOADOUTSKIN_HELP)] + [ConCommand(commandName = "nocooldowns", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.LOADOUTSKIN_HELP)] + public static void CC_Cooldown(ConCommandArgs args) + { + if (!args.senderBody) + { + return; + } + NoCooldowns = !NoCooldowns; + GenericSkill[] slots = args.senderBody.GetComponents(); + foreach (GenericSkill slot in slots) + { + if (NoCooldowns == true) + { + slot.cooldownOverride = 0.001f; + } + else + { + slot.cooldownOverride = 0; + } + } + Log.MessageNetworked(String.Format(NoCooldowns ? Lang.SETTING_ENABLED : Lang.SETTING_DISABLED, "No Skill Cooldowns"), args); + } + + + + [ConCommand(commandName = "invis", flags = ConVarFlags.None, helpText = "Turn off your model for screenshots")] + [ConCommand(commandName = "model", flags = ConVarFlags.None, helpText = "Turn off your model for screenshots")] + public static void CC_TurnOffModel(ConCommandArgs args) + { + + GameObject mdl = args.senderBody.GetComponent().modelTransform.gameObject; + mdl.SetActive(!mdl.activeSelf); + Log.MessageNetworked(String.Format(!mdl.activeSelf ? Lang.SETTING_ENABLED : Lang.SETTING_DISABLED, "Invisible Model"), args); + + } + + [ConCommand(commandName = "hud", flags = ConVarFlags.None, helpText = "Toggle hud_enable. Enable/disable the HUD.")] + [ConCommand(commandName = "ui", flags = ConVarFlags.None, helpText = "Toggle hud_enable. Enable/disable the HUD.")] + public static void CC_ToggleHUD(ConCommandArgs args) + { + RoR2.UI.HUD.cvHudEnable.SetBool(!RoR2.UI.HUD.cvHudEnable.value); + Log.MessageNetworked(String.Format(RoR2.UI.HUD.cvHudEnable.value ? Lang.SETTING_ENABLED : Lang.SETTING_DISABLED, "Hud"), args); + + } + + + + } } diff --git a/Code/DT-Commands/Spawners.cs b/Code/DT-Commands/Spawners.cs index 31c2f08..0b0740d 100644 --- a/Code/DT-Commands/Spawners.cs +++ b/Code/DT-Commands/Spawners.cs @@ -46,6 +46,7 @@ private static void CCSpawnInteractable(ConCommandArgs args) Log.MessageNetworked(Lang.INTERACTABLE_NOTFOUND, args, LogLevel.MessageClientOnly); return; } + int amount = args.TryGetArgInt(1).GetValueOrDefault(1); // Putting interactables with a collider just far enough to not cause any clipping // or spawn under the character's feet. The few exceptions with MeshCollider aren't // treated but they aren't much of an issue. @@ -81,10 +82,23 @@ private static void CCSpawnInteractable(ConCommandArgs args) var direction = args.senderBody.inputBank.aimDirection; position = position + (args.senderBody.radius + distance) * new Vector3(direction.x, 0f, direction.z); } - var result = isc.DoSpawn(position, new Quaternion(), new DirectorSpawnRequest(isc, null, RoR2Application.rng)); - if (!result.success) + if (amount > 100) { - Log.MessageNetworked("Failed to spawn interactable.", args, LogLevel.MessageClientOnly); + amount = 100; + Log.MessageNetworked($"Limited to 100, please don't spawn too many things at once.", args, LogLevel.MessageClientOnly); + } + int failed = 0; + for (int i = 0; i < amount; i++) + { + var result = isc.DoSpawn(position, new Quaternion(), new DirectorSpawnRequest(isc, null, RoR2Application.rng)); + if (!result.success) + { + failed++; + } + } + if (failed > 0) + { + Log.MessageNetworked($"Failed to spawn {failed} interactable.", args, LogLevel.MessageClientOnly); } } @@ -193,7 +207,11 @@ private static void CCSpawnAI(ConCommandArgs args) Log.MessageNetworked(String.Format(Lang.PARSE_ERROR, "count", "int"), args, LogLevel.MessageClientOnly); return; } - + if (amount > 100) + { + amount = 100; + Log.MessageNetworked($"Limited to 100, please dont spawn too many things at once.", args, LogLevel.MessageClientOnly); + } EliteDef eliteDef = null; if (args.Count > 2 && args[2] != Lang.DEFAULT_VALUE) { diff --git a/Code/Hooks.cs b/Code/Hooks.cs index 39d8b6a..c16c367 100644 --- a/Code/Hooks.cs +++ b/Code/Hooks.cs @@ -14,7 +14,7 @@ using UnityEngine; using UnityEngine.Networking; using Console = RoR2.Console; - + namespace DebugToolkit { public sealed class Hooks @@ -26,8 +26,9 @@ public sealed class Hooks private static int[] autoCompleteIndices; private static On.RoR2.Console.orig_RunCmd _origRunCmd; - private static bool buddha; - private static bool god; + public static bool buddha; + public static bool buddhaMonsters; + public static bool god; private static GameObject commandSignatureText; private static CombatDirector bossDirector; @@ -93,12 +94,88 @@ public static void InitializeHooks() Run.onRunDestroyGlobal += Command_Noclip.DisableOnRunDestroy; //Buddha Mode hook - On.RoR2.HealthComponent.TakeDamage += NonLethalDamage; + //On.RoR2.HealthComponent.TakeDamage += NonLethalDamage; + On.RoR2.CharacterBody.Start += SetBuddhaMode; On.RoR2.CharacterMaster.Awake += SetGodMode; // Console logging fixes - temporary IL.RoR2.Console.ShowHelpText += FixCommandHelpText; IL.RoR2.Console.CCFind += FixCCFind; + + On.RoR2.ConCommandArgExtensions.TryGetArgBodyIndex += AllowBodyIndexToBeUsedInsteadOfBodyName; + On.RoR2.UserProfile.CCLoadoutSetSkillVariant += LoadoutSetSkillVariant_AcceptSELF; + } + + private static void LoadoutSetSkillVariant_AcceptSELF(On.RoR2.UserProfile.orig_CCLoadoutSetSkillVariant orig, ConCommandArgs args) + { + string isSelf = args.TryGetArgString(0); + if(isSelf != null && isSelf.ToUpperInvariant() == "SELF") + { + if (args.sender == null) + { + Log.Message("Can't choose self if not in-game!", Log.LogLevel.Error); + return; + } + BodyIndex body = BodyIndex.None; + if (args.senderBody) + { + body = args.senderBody.bodyIndex; + } + else + { + if (args.senderMaster && args.senderMaster.bodyPrefab) + { + body = args.senderMaster.bodyPrefab.GetComponent().bodyIndex; + } + else + { + body = args.sender.bodyIndexPreference; + } + } + args.userArgs[0] = ((int)body).ToString(); + + } + orig(args); + } + + private static BodyIndex? AllowBodyIndexToBeUsedInsteadOfBodyName(On.RoR2.ConCommandArgExtensions.orig_TryGetArgBodyIndex orig, ConCommandArgs args, int index) + { + BodyIndex? temp = orig(args, index); + if (temp == null) + { + if (index < args.userArgs.Count) + { + return new BodyIndex?((BodyIndex)args.TryGetArgInt(index).GetValueOrDefault(-1)); + } + } + return temp; + } + + private static void SetBuddhaMode(On.RoR2.CharacterBody.orig_Start orig, CharacterBody self) + { + orig(self); + if (self.isPlayerControlled) + { + if (buddha) + { + self.bodyFlags |= CharacterBody.BodyFlags.Buddha; + } + if (PlayerCommands.NoCooldowns) + { + GenericSkill[] slots = self.GetComponents(); + foreach (GenericSkill slot in slots) + { + if (slot.finalRechargeInterval != 0) + { + slot.cooldownOverride = 0.001f; + } + } + } + } + else if(buddhaMonsters) + { + self.bodyFlags |= CharacterBody.BodyFlags.Buddha; + } } private static void ToggleConsoleWindowWithCustomKey(ILContext il) diff --git a/Code/Lang.cs b/Code/Lang.cs index 0dc8046..4f61033 100644 --- a/Code/Lang.cs +++ b/Code/Lang.cs @@ -12,7 +12,7 @@ public const string BIND_DELETE_ARGS = "Requires 1 argument: {key}", CHANGETEAM_ARGS = "Requires 1 (2 if from server) argument: {team} [player:]", CHARGEZONE_ARGS = "Requires 1 argument: {charge}", - CREATEPICKUP_ARGS = "Requires 1 (3 if from server) argument: {object (item|equip|'lunarcoin'|'voidcoin')} [type ('permanent'|'temp'):'permanent'] [search ('item'|'equip'|'both'):'both'] *[player:]", + CREATEPICKUP_ARGS = "Requires 1 (3 if from server) argument: {object (item|equip|drone|'lunarcoin'|'voidcoin')} [search ('item'|'equip'|'drone'|'all'|'pickup'):'all'] [type ('permanent'|'temp'):'permanent'] player:]", CREATEPOTENTIAL_ARGS = "Requires 0 (3 if from server) arguments: [droptable (droptable|'all'):'all'] [count:3] *[player:]", DELAY_ARGS = "Requires 2 arguments: {delay} {console_commands}", DUMPSTATE_ARGS = "Requires 0 (1 if from server) argument: [target (player|'pinged'):]", @@ -23,22 +23,29 @@ public const string GIVEBUFF_ARGS = "Requires 1 (4 if from server) arguments: {buff} [count:1] [duration:0] [target (player|'pinged'):]", GIVEDOT_ARGS = "Requires 1 (4 if from server) argument: {dot} [count:1] [target (player|'pinged'):] [attacker (player|'pinged'):]", GIVEEQUIP_ARGS = "Requires 1 (2 if from server) argument: {equip (equip|'random')} [target (player|'pinged'|'evolution'|'simulacrum'|'voidfields'|'devotion'):]", - GIVEITEM_ARGS = "Requires 1 (3 if from server) argument: {item} [count:1] [type ('permanent'|'temp'):'permanent'] [target (player|'pinged'|'evolution'|'simulacrum'|'voidfields'|'devotion'):]", + RANDOMEQUIP_ARGS = "Requires 0 (1 if from server) argument: [target (player|'pinged'):]", + //GIVEITEM_ARGS = "Requires 1 (3 if from server) argument: {item} [count:1] [type ('permanent'|'temp'|'channeled'):'permanent'] [target (player|'pinged'|'evolution'|'simulacrum'|'voidfields'|'devotion'):]", + GIVEITEM_ARGS = "Requires 1 (3 if from server) argument: {item} [count:1] [itemTypes:'permanent'] [target (player|'pinged'|'evolution'|'simulacrum'|'voidfields'|'devotion'):]", + GIVEDRONE_ARGS = "Requires 1 (2 if from server) argument: {drone} [count:1] [tier:1] [target (player|'pinged'):]", GIVELUNAR_ARGS = "Requires 0 arguments: [amount:1]", GIVEMONEY_ARGS = "Requires 1 argument: {amount} [target (player|'all')]", + MONEY_ARGS = "Requires 0 argument: [target (player|'all')]", HEAL_ARGS = "Requires 1 argument: {amount} [target (player|'pinged'):]", HURT_ARGS = "Requires 1 argument: {amount} [target (player|'pinged'):]", KICK_ARGS = "Requires 1 argument: {player}", KILLALL_ARGS = "Requires 0 arguments: [team:Monster]", LISTSKIN_ARGS = "Requires 0 arguments: [selection (body|'all'|'body'|'self'):'all']", LISTQUERY_ARGS = "Requires 0 arguments: [query]", + LISTMODS_ARGS = "Requires 0 arguments: [filterByRequiredByAll (0|1):0/false]", LOADOUTSKIN_ARGS = "Requires 2 argument: {body_name (body|'self')} {skin_index}", + LOADOUTSKILL_ARGS = "Requires 2 argument: {skill_slot} {skill_variant}", NEXTBOSS_ARGS = "Requires 1 argument: {director_card} [count:1] [elite:None]", NEXTSTAGE_ARGS = "Requires 0 arguments: [specific_stage]", NO_ARGS = "Requires 0 arguments.", PERM_MOD_ARGS = "Requires 2 arguments: {permission_level} {player}", POSTSOUNDEVENT_ARGS = "Requires 1 argument: {sound_event (event_name|event_id)}", - RANDOMITEM_ARGS = "Requires 1 (3 if from server) argument: {count} [droptable (droptable|'all'):'all'] [type ('permanent'|'temp'):'permanent'] [target (player|'pinged'|'evolution'|'simulacrum'|'voidfields'|'devotion'):]", + RANDOMITEM_ARGS = "Requires 1 (3 if from server) argument: {count} [tier (tier|'all'):'\"0,1,2,4\"'] [type ('permanent'|'temp'):'permanent'] [target (player|'pinged'|'evolution'|'simulacrum'|'voidfields'|'devotion'):]", + RANDOMITEM2_ARGS = "Requires 1 (3 if from server) argument: {count} [allowLunar (0|1):0/false] [allowVoid (0|1):0/false] [target (player|'pinged'|'evolution'|'simulacrum'|'voidfields'|'devotion'):]", REMOVEALLBUFFS_ARGS = "Requires 0 (2 if from server) arguments: [timed (0|1):0/false] [target (player|'pinged'):]", REMOVEALLDOTS_ARGS = "Requires 0 (1 if from server) arguments: [target (player|'pinged'):]", REMOVEALLITEMS_ARGS = "Requires 0 (1 if from server) arguments: [target (player|'pinged'|'evolution'|'simulacrum'|'voidfields'|'devotion'):]", @@ -54,9 +61,9 @@ public const string SEED_ARGS = "Requires 0 or 1 argument: [new_seed]", SETARTIFACT_ARGS = "Requires 1 (2 if using 'all') argument: {artifact (artifact|'all')} [enable (0|1)]", SPAWNAI_ARGS = "Requires 1 argument: {ai} [count:1] [elite:None] [braindead (0|1):0/false] [team:Monster]", - SPAWNAS_ARGS = "Requires 1 (2 if from server) argument: {body} [player:]", + SPAWNAS_ARGS = "Requires 1 (3 if from server) argument: {body} [permanent (0|1):0/false] [player:]", SPAWNBODY_ARGS = "Requires 1 argument: {body}", - SPAWNINTERACTABLE_ARGS = "Requires 1 argument: {interactable}", + SPAWNINTERACTABLE_ARGS = "Requires 1 argument: {interactable} [count:1]", SPAWNPORTAL_ARGS = "Requires 1 argument: {portal ('artifact'|'blue'|'celestial'|'deepvoid'|'gold'|'green'|'null'|'void')}", TIMESCALE_ARGS = "Requires 1 argument: {time_scale}", TRUEKILL_ARGS = "Requires 0 (1 if from server) arguments: [player:]" @@ -69,12 +76,15 @@ public const string BIND_HELP = "Bind a key to execute specific commands. " + BIND_ARGS, BIND_DELETE_HELP = "Remove a custom bind from the macro system of DebugToolkit. " + BIND_DELETE_ARGS, BIND_RELOAD_HELP = "Reload the macro system of DebugToolkit. " + NO_ARGS, - BUDDHA_HELP = "Become immortal. Instead of refusing damage you just refuse to take lethal damage.\nIt works by giving all damage a player takes DamageType.NonLethal. " + ENABLE_ARGS, + //BUDDHA_HELP = "Become immortal. Instead of refusing damage you just refuse to take lethal damage.\nIt works by giving all damage a player takes DamageType.NonLethal. " + ENABLE_ARGS, + BUDDHA_HELP = "Players become immortal, but remain attackable. " + ENABLE_ARGS, + BUDDHA_HELP2 = "Enemies become immortal, but remain attackable. " + ENABLE_ARGS, CHANGETEAM_HELP = "Change the specified player to the specified team. " + CHANGETEAM_ARGS, CHARGEZONE_HELP = "Set the charge of all active holdout zones. " + CHARGEZONE_ARGS, CREATEPICKUP_HELP = "Creates a PickupDroplet infront of your position. " + CREATEPICKUP_ARGS, CREATEPOTENTIAL_HELP = "Creates a potential PickupDroplet infront of your position. " + CREATEPOTENTIAL_ARGS, - CURSORTELEPORT_HELP = "Teleport you to where your cursor is currently aiming at. " + NO_ARGS, + CURSORTELEPORT_HELP = "Teleports you to where your cursor is currently aiming at. " + NO_ARGS, + GOTOBOSS_HELP = "Teleports you to the Teleporter, first Boss creature or specific arena depending on the stage. " + NO_ARGS, DELAY_HELP = "Execute any commands after a delay in seconds. " + DELAY_ARGS, DUMPBUFFS_HELP = "List the buffs/debuffs of all spawned bodies. " + NO_ARGS, DUMPINVENTORIES_HELP = "List the inventory items and equipment of all spawned bodies. " + NO_ARGS, @@ -86,9 +96,14 @@ public const string GIVEBUFF_HELP = "Gives the specified buff to a character. A duration of 0 means permanent. " + GIVEBUFF_ARGS, GIVEDOT_HELP = "Gives the specified DoT to a character. " + GIVEDOT_ARGS, GIVEEQUIP_HELP = "Gives the specified equipment to a target. " + GIVEEQUIP_ARGS, + RANDOMEQUIP_HELP = "Gives a random equipment to a target. " + RANDOMEQUIP_ARGS, GIVEITEM_HELP = "Gives the specified item to a target. " + GIVEITEM_ARGS, - GIVELUNAR_HELP = "Gives a lunar coin to you. " + GIVELUNAR_ARGS, + GIVEDRONE_HELP = "Summons the specified drone to a target. " + GIVEDRONE_ARGS, + GIVELUNAR_HELP = "Gives amount of lunar coin to you. " + GIVELUNAR_ARGS, + GIVEVOID_HELP = "Gives amount of void markers to you. " + GIVELUNAR_ARGS, GIVEMONEY_HELP = "Gives the specified amount of money to the specified player. " + GIVEMONEY_ARGS, + NO_MONEY_HELP = "Sets money to 0 for specified player. " + GIVEMONEY_ARGS, + ALLMONEY_HELP = "Sets money to 2'000'000'000 for specified player. " + GIVEMONEY_ARGS, GOD_HELP = "Become invincible. " + ENABLE_ARGS, HEAL_HELP = "Heal yourself or another target. " + HEAL_ARGS, HURT_HELP = "Deal generic damage to yourself or another target. " + HURT_ARGS, @@ -102,6 +117,8 @@ public const string LISTDOT_HELP = "List all DoTs. " + LISTQUERY_ARGS, LISTELITE_HELP = "List all Elites and their language invariants. " + LISTQUERY_ARGS, LISTEQUIP_HELP = "List all equipment and their availability. " + LISTQUERY_ARGS, + LISTDRONE_HELP = "List all drones and their availability. " + LISTQUERY_ARGS, + LISTPICKUP_HELP = "List all pickups and their availability. " + LISTQUERY_ARGS, LISTINTERACTABLE_HELP = "Lists all interactables. " + LISTQUERY_ARGS, LISTITEMTIER_HELP = "List all item tiers. " + LISTQUERY_ARGS, LISTITEM_HELP = "List all items and their availability. " + LISTQUERY_ARGS, @@ -112,7 +129,10 @@ public const string LISTTEAM_HELP = "List all Teams and their language invariants. " + LISTQUERY_ARGS, LOADOUTSKIN_HELP = "Change your loadout's skin. " + LOADOUTSKIN_ARGS, LOCKEXP_HELP = "Prevent Experience gain. " + ENABLE_ARGS, + NOCOOLDOWN_HELP = "Toggles your Skill Cooldowns", MACRO_DTZOOM_HELP = "Gives you 20 hooves and 200 feathers for getting around quickly.", + MACRO_DTDAMAGE_HELP = "Gives you a lot of BoostDamage hidden item.", + MACRO_SCANNER_HELP = "Gives you 100 boostEquipmentRecharge and the Radar Scanner equipment to easily search stages.", MACRO_LATEGAME_HELP = "Sets the current run to the 'lategame' as defined by HG. This command is DESTRUCTIVE.", MACRO_MIDGAME_HELP = "Sets the current run to the 'midgame' as defined by HG. This command is DESTRUCTIVE.", NEXTBOSS_HELP = "Sets the next teleporter/simulacrum boss to the specified boss. " + NEXTBOSS_ARGS, @@ -120,12 +140,14 @@ public const string NEXTWAVE_HELP = "Advance to the next Simulacrum wave. " + NO_ARGS, NOCLIP_HELP = "Allow flying and going through objects. Sprinting will double the speed. " + ENABLE_ARGS, NOENEMIES_HELP = "Prevent Monster spawning. " + ENABLE_ARGS, + NOINTERACTABLES_HELP = "Prevent random Interactables from spawning. " + ENABLE_ARGS, PERM_ENABLE_HELP = "Enable or disable the permission system." + ENABLE_ARGS, PERM_MOD_HELP = "Change the permission level of the specified playerid/username" + PERM_MOD_ARGS, PERM_RELOAD_HELP = "Reload the permission system, updates user and commands permissions.", POSTSOUNDEVENT_HELP = "Post a sound event to the AkSoundEngine (WWise) either by its event name or event ID. " + POSTSOUNDEVENT_ARGS, PREVENT_PROFILE_WRITING_HELP = "Prevent saving the user profile to avoid bogus data. " + ENABLE_ARGS, RANDOMITEM_HELP = "Generate random items from the available item tiers. " + RANDOMITEM_ARGS, + RANDOMITEM_HELP2 = "Grant randoms of normal tiers with option for Lunar/Voids. " + RANDOMITEM_ARGS, RELOADCONFIG_HELP = "Reload all default config files from all loaded plugins.", REMOVEALLBUFFS_HELP = "Removes all buffs from a character. " + REMOVEALLBUFFS_ARGS, REMOVEALLDOTS_HELP = "Removes all DoTs from a character. " + REMOVEALLDOTS_ARGS, @@ -149,17 +171,21 @@ public const string SPAWNPORTAL_HELP = "Spawns a portal in front of the player. " + SPAWNPORTAL_ARGS, STOPTIMER_HELP = "Pause/unpause the run timer. " + ENABLE_ARGS, TIMESCALE_HELP = "Sets the Time Delta. " + TIMESCALE_ARGS, - TRUEKILL_HELP = "Ignore Dio's and kill the entity. " + TRUEKILL_ARGS + TRUEKILL_HELP = "Ignore Dio's and God and kill the entity. " + TRUEKILL_ARGS ; // Messages public const string - CREATEPICKUP_AMBIGIOUS_2 = "Could not choose between {0} and {1}, please be more precise. Consider using 'equip' or 'item' as the second argument.", - CREATEPICKUP_NOTFOUND = "Could not find any item nor equipment with that name.", + CREATEPICKUP_AMBIGIOUS_4 = "Found multiple results. Please be more precise or specify using 'item', 'equip', 'drone'\n{0}", + //CREATEPICKUP_AMBIGIOUS_3 = "Could not choose between {0}\n{1}\n{2}, please be more precise. Specify in second argument using 'item', 'equip' or 'drone'", + //CREATEPICKUP_AMBIGIOUS_2 = "Could not choose between {0}\n{1}, please be more precise. Specify in second argument using 'item', 'equip' or 'drone'", + CREATEPICKUP_NOTFOUND = "Could not find any item, equipment or drone with that name or index.", CREATEPICKUP_SUCCESS_1 = "Successfully created the pickup {0}.", CREATEPICKUP_SUCCESS_2 = "Successfully created a potential with {0} options.", GIVELUNAR_2 = "{0} {1} lunar coin(s).", - GIVEOBJECT = "Gave {0} {1} to {2}.", + GIVEVOIDC_2 = "{0} {1} void marker(s).", + GIVEOBJECT = "Gave {0} {3} {1} to {2}.", + GIVEDRONE = "Summoned {0} {1} (Tier {3}) to {2}.", OBSOLETEWARNING = "This command has become obsolete and will be removed in the next version. ", NETWORKING_OTHERPLAYER_4 = "{0}({1}) issued: {2} {3}", NOMESSAGE = "Yell at the modmakers if you see this message!", @@ -191,7 +217,7 @@ public const string NOTINARUN_ERROR = "This command only works when in a Run!", NOTINASIMULACRUMRUN_ERROR = "Must be in a Simulacrum Run!", NOTINVOIDFIELDS_ERROR = "Must be on Void Fields!", - OBJECT_NOTFOUND = "No {0} with the name \"{1}\" could be found.", + OBJECT_NOTFOUND = "No {0} with the name or index \"{1}\" could be found.", PARSE_ERROR = "Unable to parse {0} to {1}.", PINGEDBODY_NOTFOUND = "Pinged target not found. Either the last ping was not a character, or it has been destroyed since.", PLAYER_NOTFOUND = "Specified player not found or isn't alive. Please use list_player for options.", @@ -209,6 +235,8 @@ public const string DEFAULT_VALUE = "", DEVOTION = "DEVOTION", EQUIP = "EQUIP", + DRONE = "DRONE", + PICKUP = "PICKUP", EVOLUTION = "EVOLUTION", ITEM = "ITEM", PINGED = "PINGED", diff --git a/Code/StringFinder.cs b/Code/StringFinder.cs index 65d800a..6cce321 100644 --- a/Code/StringFinder.cs +++ b/Code/StringFinder.cs @@ -359,6 +359,16 @@ public ItemIndex GetItemFromPartial(string name) return GetItemsFromPartial(name).DefaultIfEmpty(ItemIndex.None).First(); } + public DroneIndex GetDroneFromPartial(string name) + { + return GetDronesFromPartial(name).DefaultIfEmpty(DroneIndex.None).First(); + } + + public PickupIndex GetPickupFromPartial(string name) + { + return GetPickupsFromPartial(name).DefaultIfEmpty(PickupIndex.none).First(); + } + /// /// Returns an iterator of ItemIndex's when provided with an index or partial/invariant. /// @@ -395,6 +405,70 @@ public IEnumerable GetItemsFromPartial(string name) } } + public IEnumerable GetDronesFromPartial(string name) + { + if (TextSerialization.TryParseInvariant(name, out int i)) + { + var index = (DroneIndex)i; + //if (DroneCatalog.IsIndexValid(index)) + if (index < (DroneIndex)DroneCatalog.droneCount) + { + yield return index; + } + yield break; + } + name = name.ToUpperInvariant(); + var matches = new List(); + foreach (var drone in DroneCatalog.allDroneDefs) + { + var langInvar = GetLangInvar(drone.nameToken).ToUpper(); + if (drone.name.ToUpper().Contains(name) || langInvar.Contains(name)) + { + matches.Add(new MatchSimilarity + { + similarity = Math.Max(GetSimilarity(drone.name, name), GetSimilarity(langInvar, name)), + item = drone.droneIndex + }); + } + } + foreach (var match in matches.OrderByDescending(m => m.similarity)) + { + yield return (DroneIndex)match.item; + } + } + + public IEnumerable GetPickupsFromPartial(string name) + { + if (TextSerialization.TryParseInvariant(name, out int i)) + { + var index = i; + if (index < PickupCatalog.pickupCount) + { + yield return PickupIndex.none; + } + yield break; + } + name = name.ToUpperInvariant(); + var matches = new List(); + foreach (var pickup in PickupCatalog.allPickups) + { + var langInvar = GetLangInvar(pickup.nameToken).ToUpper(); + if (pickup.internalName.ToUpper().Contains(name) || langInvar.Contains(name)) + { + //yield return pickup.pickupIndex; + matches.Add(new MatchSimilarity + { + similarity = Math.Max(GetSimilarity(pickup.internalName, name), GetSimilarity(langInvar, name)), + item = pickup.pickupIndex + }); + } + } + foreach (var match in matches.OrderByDescending(m => m.similarity)) + { + yield return (PickupIndex)match.item; + } + } + /// /// Returns a NetworkUser when provided with an index or partial/invariant. /// From 0ea5623fc1616880ba20785a3ca93d4529d288f1 Mon Sep 17 00:00:00 2001 From: Wolfo Date: Sun, 28 Dec 2025 18:23:58 +0100 Subject: [PATCH 02/25] probably finished --- CHANGELOG.md | 36 +++- Code/AutoCompletion/AutoCompleteManager.cs | 10 +- Code/DT-Commands/Buffs.cs | 9 +- Code/DT-Commands/CurrentRun.cs | 75 ++++++- Code/DT-Commands/Drones.cs | 213 +++++++++++++++++++ Code/DT-Commands/Items.cs | 35 +++- Code/DT-Commands/Macros.cs | 11 + Code/DT-Commands/Miscellaneous.cs | 42 +++- Code/DT-Commands/Money.cs | 10 +- Code/DT-Commands/PlayerCommands.cs | 229 ++++++++++++++++++++- Code/Hooks.cs | 7 +- Code/Lang.cs | 33 ++- DebugToolkit.csproj | 2 +- 13 files changed, 639 insertions(+), 73 deletions(-) create mode 100644 Code/DT-Commands/Drones.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index aed4746..3998420 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,26 +5,38 @@ * Added commands: * 'give_drone': Summons drone, specified amount and tier - * 'list_drone', 'list_pickups' - * 'list_mods': Get internal name of all installed mod. - * 'buddhaenemy', 'invulenemy': Buddha mode for all enemies, to make them unkillable. - * 'goto_boss' -> Teleports you to boss, teleporter or boss arenas on stage, so you don't have to fly to Mithrix 100 times in testing. - * 'model': hides model, for screenshotting/recording. + * 'remove_all_drones': Removes all drones, leaving no bodies. + * 'kill_minions': Kills all minions, leaving dead drones. + * 'list_drone': List drone names and ids. + + * 'set_ .. damage, attackspeed, health, regen, armor, movespeed' Sets the stat to the specified value, for the target, for that life; For clean testing. + * 'reset_stats' Undoes changes from 'set_..' commands. * 'nocooldowns': disables your skill cooldowns + + * 'list_pickups': List pickup names and ids. + * 'list_mods': Lists all loaded mods and if they are tagged as RequiredByAll. Useful to get internal names to check for. + * 'buddhaenemy', 'invulenemy': Buddha mode for all enemies, to make them unkillable. + * 'goto_boss': Teleports you to boss, teleporter or boss arenas on stage, (so you don't have to fly to Mithrix 100 times) + * 'hide_model': hides model, for screenshotting/recording. + * 'evolve_lemurian': Triggers Artifact of Devotion evolution. * 'give_voidcoin': Gives Void Markers. - * 'no_interactables': Prevent interactables + * 'no_interactables': Prevent interactables from spawning + * 'toggle_time' Toggles 'time_scale' between 0 and what it it was before. + * Added macro/short commands: * 'dtscanner' -> 100 BoostEquipmentRechrage & Radar Scanner equip for easy map searching. * 'dtdamage' -> x1000000 damage macro. + * 'dtpeace' -> 'kill_all' monsters & voids and 'no_enemies true' * 'random_equip' macro for 'give_equip random' * 'rich', -> Set money to 2 billion. * 'poor' -> Set money to 0. * 'hud': shorthand toggle for 'hud_enable' * 'skill': shorthand for 'loadout_set_skill_variant self' + * 'skin': shorthand for 'loadout_set_skin_variant self' * 'unlimited_junk': Toggle for 'junk_unlimited' - * 'cleanse': Alt for 'remove_all_buffs' + * 'cleanse': Alt for 'remove_all_buffs 0 & 1' * Updated command functionality: * Item commands can now grant/remove channeled items @@ -32,14 +44,18 @@ * 'spawn_interactable' now also shows interactable names in auto complete. * 'spawn_interactable' now accepts amount. * 'spawn_as' now has second argument to permanently spawn as the new body. (Like prior to AC behaviour) //Default False - * 'create_pickup' now supports dropping drones or pickups. - * 'create_pickup' switched {type} and {permanent/temp} argument spots. + * 'create_pickup' now supports dropping drones & pickups. + * 'create_pickup' switched {search} and {permanent/temp} argument spots. * 'give_equip -1' now removes your equipment. * 'give_buff' now works with negative amount for removing. - * 'true_kill' now bypasses godmode. * 'loadout_set_skill_variant' now accepts 'self' * 'random_items' changed default value to not give Lunars & Voids. + * 'hurt' second optional argument to bypass armor/damage calculations. + * 'kill_all' no value given now kills Monster & Void teams. + * 'kill_all' second optional argument to bypass revives. (Does not bypass Godmode) + * 'true_kill' now bypasses godmode. + * Amount of spawned interactables/monsters/drones by commands capped at a 100 per command, to not crash the game if you mistype. * Fixed 'god 0/1'/'buddha 0/1' not setting the toggle's state. * Fixed 'loadout_set_skin_variant' crashing the game. diff --git a/Code/AutoCompletion/AutoCompleteManager.cs b/Code/AutoCompletion/AutoCompleteManager.cs index 8d2e1d1..cc065af 100644 --- a/Code/AutoCompletion/AutoCompleteManager.cs +++ b/Code/AutoCompletion/AutoCompleteManager.cs @@ -97,14 +97,16 @@ internal static void RegisterAutoCompleteCommands() parser.RegisterDynamicVariable("player", NetworkUser.instancesList, "userName"); parser.RegisterStaticVariable("itemTypes", new string[] { - //"0|None", "1|Permanent", "2|Temp", "3|Channelled", - }, - 1 + },1 ); - + parser.RegisterStaticVariable("itemTypesNoChanneled", new string[] { + "1|Permanent", + "2|Temp", + }, 1 + ); parser.Scan(System.Reflection.Assembly.GetExecutingAssembly()); } diff --git a/Code/DT-Commands/Buffs.cs b/Code/DT-Commands/Buffs.cs index 7d28ea9..b15616c 100644 --- a/Code/DT-Commands/Buffs.cs +++ b/Code/DT-Commands/Buffs.cs @@ -98,8 +98,9 @@ private static void CCGiveBuff(ConCommandArgs args) } if (duration < 0f) { + duration = 0; Log.MessageNetworked(String.Format(Lang.NEGATIVE_ARG, "duration"), args, LogLevel.MessageClientOnly); - return; + //return; } var target = ParseTarget(args, 3); @@ -141,7 +142,7 @@ private static void CCGiveBuff(ConCommandArgs args) body.AddBuff(buff); } } - Log.MessageNetworked(string.Format(Lang.GIVEOBJECT, iCount, name, target.name, ""), args); + Log.MessageNetworked(string.Format(Lang.GIVEBUFF, iCount, name, target.name, ""), args); } else { @@ -163,7 +164,7 @@ private static void CCGiveBuff(ConCommandArgs args) body.AddTimedBuff(buff, duration); } } - Log.MessageNetworked($"Gave {iCount} {name} to {target.name} for {duration} seconds", args); + Log.MessageNetworked($"Gave {iCount} {name} to {target.name} for {duration} seconds", args); } } @@ -344,7 +345,7 @@ private static void CCCleanse(ConCommandArgs args) { body.SetBuffCount((BuffIndex)i, 0); } - Log.MessageNetworked($"Cleansed {target.name}", args); + Log.MessageNetworked($"Cleansed {target.name} of all buffs.", args); } [ConCommand(commandName = "remove_all_buffs", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.REMOVEALLBUFFS_HELP)] diff --git a/Code/DT-Commands/CurrentRun.cs b/Code/DT-Commands/CurrentRun.cs index 662d0ad..5be2033 100644 --- a/Code/DT-Commands/CurrentRun.cs +++ b/Code/DT-Commands/CurrentRun.cs @@ -230,31 +230,84 @@ private static void CCKillAll(ConCommandArgs args) Log.MessageNetworked(Lang.NOTINARUN_ERROR, args, LogLevel.MessageClientOnly); return; } - TeamIndex team = TeamIndex.Monster; + bool trueKill = false; + if (args.Count > 1 && args[1] != Lang.DEFAULT_VALUE && !Util.TryParseBool(args[1], out trueKill)) + { + Log.MessageNetworked(String.Format(Lang.PARSE_ERROR, "trueKill", "int or bool"), args, LogLevel.MessageClientOnly); + return; + } + if (args.Count > 0 && args[0] != Lang.DEFAULT_VALUE) { + TeamIndex team = TeamIndex.Monster; team = StringFinder.Instance.GetTeamFromPartial(args[0]); if (team == StringFinder.TeamIndex_NotFound) { Log.MessageNetworked(Lang.TEAM_NOTFOUND, args, LogLevel.MessageClientOnly); return; } - } - int count = 0; - foreach (var teamComponent in TeamComponent.GetTeamMembers(team).ToList()) - { - var healthComponent = teamComponent.GetComponent(); - if (healthComponent) + int count = 0; + foreach (var teamComponent in TeamComponent.GetTeamMembers(team).ToList()) { - healthComponent.Suicide(null); - if (!healthComponent.alive) + if (trueKill && teamComponent.body.master) { + teamComponent.body.master.TrueKill(); count++; } + else + { + var healthComponent = teamComponent.GetComponent(); + if (healthComponent) + { + + healthComponent.Suicide(null); + if (!healthComponent.alive) + { + count++; + } + } + } + + + } + string a = (trueKill ? "True " : "" ); + Log.MessageNetworked($"{a}Killed {count} of team {team}.", args); + } + else + { + int count = 0; + int countV = 0; + foreach (var teamComponent in TeamComponent.GetTeamMembers(TeamIndex.Monster).ToList()) + { + var healthComponent = teamComponent.GetComponent(); + if (healthComponent) + { + healthComponent.Suicide(null); + if (!healthComponent.alive) + { + count++; + } + } + } + foreach (var teamComponent in TeamComponent.GetTeamMembers(TeamIndex.Void).ToList()) + { + var healthComponent = teamComponent.GetComponent(); + if (healthComponent) + { + healthComponent.Suicide(null); + if (!healthComponent.alive) + { + countV++; + } + } } + Log.MessageNetworked($"Killed {count} of team {TeamIndex.Monster}.", args); + Log.MessageNetworked($"Killed {countV} of team {TeamIndex.Void}.", args); } - Log.MessageNetworked($"Killed {count} of team {team}.", args); + + + } [ConCommand(commandName = "time_scale", flags = ConVarFlags.Engine | ConVarFlags.ExecuteOnServer, helpText = Lang.TIMESCALE_HELP)] @@ -747,7 +800,7 @@ internal static void Invoke(float scale) private void RpcApplyTimescale(float scale) { Time.timeScale = scale; - Message("Timescale set to: " + scale + ". "); + Message("Timescale set to: " + scale + " "); } } } diff --git a/Code/DT-Commands/Drones.cs b/Code/DT-Commands/Drones.cs new file mode 100644 index 0000000..b063556 --- /dev/null +++ b/Code/DT-Commands/Drones.cs @@ -0,0 +1,213 @@ +using RoR2; +using RoR2.Artifacts; +using System; +using System.Collections.Generic; +using System.Text; +using System.Xml.Linq; +using UnityEngine; +using UnityEngine.AddressableAssets; +using UnityEngine.Networking; +using static DebugToolkit.Log; +using static DebugToolkit.Util; + +namespace DebugToolkit.Commands +{ + class Drones + { + [ConCommand(commandName = "list_drone", flags = ConVarFlags.None, helpText = Lang.LISTDRONE_HELP)] + [AutoComplete(Lang.LISTQUERY_ARGS)] + private static void CCListDrone(ConCommandArgs args) + { + var sb = new StringBuilder(); + var arg = args.Count > 0 ? args[0] : ""; + var indices = StringFinder.Instance.GetDronesFromPartial(arg); + foreach (var index in indices) + { + var definition = DroneCatalog.GetDroneDef(index); + var realName = Language.currentLanguage.GetLocalizedStringByToken(definition.nameToken); + bool enabled = Run.instance && Run.instance.IsDroneAvailable(index); + sb.AppendLine($"[{(int)index}]{definition.name} \"{realName}\" (enabled={enabled})"); + } + var s = sb.Length > 0 ? sb.ToString().TrimEnd('\n') : string.Format(Lang.NOMATCH_ERROR, "drone", arg); + Log.MessageNetworked(s, args, LogLevel.MessageClientOnly); + } + + [ConCommand(commandName = "give_drone", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.GIVEDRONE_HELP)] + [AutoComplete(Lang.GIVEDRONE_ARGS)] + private static void CCGiveDrone(ConCommandArgs args) + { + //give_drone {name} {amount} {tier} + if (!Run.instance) + { + Log.MessageNetworked(Lang.NOTINARUN_ERROR, args, LogLevel.MessageClientOnly); + return; + } + bool isDedicatedServer = args.sender == null; + if (args.Count == 0 || (isDedicatedServer && (args.Count < 4 || args[3] == Lang.DEFAULT_VALUE))) + { + Log.MessageNetworked(Lang.INSUFFICIENT_ARGS + Lang.GIVEITEM_ARGS, args, LogLevel.MessageClientOnly); + return; + } + + int amount = 1; + if (args.Count > 1 && args[1] != Lang.DEFAULT_VALUE && !TextSerialization.TryParseInvariant(args[1], out amount)) + { + Log.MessageNetworked(String.Format(Lang.PARSE_ERROR, "count", "int"), args, LogLevel.MessageClientOnly); + return; + } + int tier = 1; + if (args.Count > 2 && args[2] != Lang.DEFAULT_VALUE && !TextSerialization.TryParseInvariant(args[2], out tier)) + { + Log.MessageNetworked(String.Format(Lang.PARSE_ERROR, "tier", "int"), args, LogLevel.MessageClientOnly); + return; + } + + var target = Buffs.ParseTarget(args, 3); + if (target.failMessage != null) + { + Log.MessageNetworked(target.failMessage, args, LogLevel.MessageClientOnly); + return; + } + if (!target.body) + { + Log.MessageNetworked("No target body found", args, LogLevel.MessageClientOnly); + return; + } + + var drone = StringFinder.Instance.GetDroneFromPartial(args[0]); + if (drone == DroneIndex.None) + { + Log.MessageNetworked(string.Format(Lang.OBJECT_NOTFOUND, "drone", args[0]), args, LogLevel.MessageClientOnly); + return; + } + DroneDef droneDef = DroneCatalog.GetDroneDef(drone); + + if (droneDef == null) + { + Log.MessageNetworked(string.Format(Lang.OBJECT_NOTFOUND, "drone", args[0]), args, LogLevel.MessageClientOnly); + return; + } + if (Run.instance.IsDroneExpansionLocked(drone)) + { + Log.MessageNetworked(string.Format(Lang.EXPANSION_LOCKED, "drone", Util.GetExpansion(droneDef.requiredExpansion)), args, LogLevel.MessageClientOnly); + return; + } + if (amount > 50) + { + amount = 50; + Log.MessageNetworked($"Limited to 50, please don't spawn too many things at once.", args, LogLevel.MessageClientOnly); + } + if (amount > 0) + { + for (int i = 0; i < amount; i++) + { + CharacterMaster newlySpawnedDrone = new MasterSummon + { + masterPrefab = droneDef.masterPrefab, + position = target.body.transform.position, + rotation = target.body.transform.rotation, + summonerBodyObject = target.body.gameObject, + ignoreTeamMemberLimit = true, + useAmbientLevel = true, + enablePrintController = true + }.Perform(); + if (tier > 1) + { + newlySpawnedDrone.inventory.GiveItemPermanent(DLC3Content.Items.DroneUpgradeHidden, (tier - 1)); + } + } + var name = droneDef.name; + Log.MessageNetworked(string.Format(Lang.GIVEDRONE, amount, name, target.name, tier), args); + } + else + { + Log.MessageNetworked("Nothing happened", args); + } + + } + + [ConCommand(commandName = "remove_all_drones", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.REMOVEALLDRONES_HELP)] + [AutoComplete(Lang.KICK_ARGS)] + private static void CCRemoveDrones(ConCommandArgs args) + { + if (!Run.instance) + { + Log.MessageNetworked(Lang.NOTINARUN_ERROR, args, LogLevel.MessageClientOnly); + return; + } + bool isDedicatedServer = args.sender == null; + if (isDedicatedServer && (args.Count < 1 || args[0] == Lang.DEFAULT_VALUE)) + { + Log.MessageNetworked(Lang.INSUFFICIENT_ARGS + Lang.KICK_ARGS, args, LogLevel.MessageClientOnly); + return; + } + + var target = Items.ParseTarget(args, 0); + if (target.failMessage != null) + { + Log.MessageNetworked(target.failMessage, args, LogLevel.MessageClientOnly); + return; + } + + + var owner = target.inventory.GetComponent(); + if (owner == null || owner.group == null || owner.group.memberCount == 0) + { + Log.MessageNetworked(string.Format(Lang.REMOVEDRONES, 0, target.name), args); + return; + } + int removedAmount = 0; + for (int i = 0; i < owner.group.memberCount; i++) + { + var master = owner.group.members[i].GetComponent(); + if (master.bodyPrefab.GetComponent().IsDrone) + { + master.DestroyBody(); + UnityEngine.Object.Destroy(master.gameObject, 1f); + removedAmount++; + } + } + Log.MessageNetworked(string.Format(Lang.REMOVEDRONES, removedAmount, target.name), args); + } + + [ConCommand(commandName = "kill_minions", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.KILL_ALL_MINIONS_HELP)] + [AutoComplete(Lang.KICK_ARGS)] + private static void CCKillMinions(ConCommandArgs args) + { + if (!Run.instance) + { + Log.MessageNetworked(Lang.NOTINARUN_ERROR, args, LogLevel.MessageClientOnly); + return; + } + bool isDedicatedServer = args.sender == null; + if (isDedicatedServer && (args.Count < 1 || args[0] == Lang.DEFAULT_VALUE)) + { + Log.MessageNetworked(Lang.INSUFFICIENT_ARGS + Lang.KICK_ARGS, args, LogLevel.MessageClientOnly); + return; + } + + var target = Items.ParseTarget(args, 0); + if (target.failMessage != null) + { + Log.MessageNetworked(target.failMessage, args, LogLevel.MessageClientOnly); + return; + } + + + var owner = target.inventory.GetComponent(); + if (owner == null || owner.group == null || owner.group.memberCount == 0) + { + Log.MessageNetworked(string.Format(Lang.Kill_MINIONS, target.name), args); + return; + } + for (int i = 0; i < owner.group.memberCount; i++) + { + var master = owner.group.members[i].GetComponent(); + master.TrueKill(); + } + Log.MessageNetworked(string.Format(Lang.Kill_MINIONS, target.name), args); + } + + + } +} diff --git a/Code/DT-Commands/Items.cs b/Code/DT-Commands/Items.cs index 1101dbb..ece8d2b 100644 --- a/Code/DT-Commands/Items.cs +++ b/Code/DT-Commands/Items.cs @@ -8,7 +8,6 @@ using UnityEngine.Networking; using static DebugToolkit.Log; using static DebugToolkit.Util; -using static Rewired.InputMapper; namespace DebugToolkit.Commands { @@ -197,6 +196,9 @@ private static void CCGiveItem(ConCommandArgs args) } var itemDef = ItemCatalog.GetItemDef(item); var name = itemDef.name; + + name = getItemTypeName(type) + name; + var amount = (args.commandName == "give_item" ? 1 : -1) * iCount; var inventory = target.inventory; if (amount > 0) @@ -207,13 +209,13 @@ private static void CCGiveItem(ConCommandArgs args) return; } GiveItem(inventory, item, amount, type); - Log.MessageNetworked(string.Format(Lang.GIVEOBJECT, amount, name, target.name, type), args); + Log.MessageNetworked(string.Format(Lang.GIVEITEM, amount, name, target.name), args); } else if (amount < 0) { amount = Math.Min(-amount, GetItemCount(inventory, item, type)); RemoveItem(inventory, item, amount, type); - Log.MessageNetworked(string.Format(Lang.REMOVEOBJECT, amount, name, target.name, type), args); + Log.MessageNetworked(string.Format(Lang.REMOVEOBJECT, amount, name, target.name), args); } else { @@ -225,6 +227,19 @@ private static void CCGiveItem(ConCommandArgs args) } } + public static string getItemTypeName(ItemType type) + { + switch (type) + { + case ItemType.Permanent: + return ""; + case ItemType.Temp: + return "Temporary "; //Saturated by 50% Temp color + //return "temporary"; //Bit hard to see in the console + } + return type.ToString(); + } + [ConCommand(commandName = "give_drone", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.GIVEDRONE_HELP)] [AutoComplete(Lang.GIVEDRONE_ARGS)] private static void CCGiveDrone(ConCommandArgs args) @@ -254,7 +269,11 @@ private static void CCGiveDrone(ConCommandArgs args) Log.MessageNetworked(String.Format(Lang.PARSE_ERROR, "tier", "int"), args, LogLevel.MessageClientOnly); return; } - + if (tier < 0) + { + Log.MessageNetworked(string.Format(Lang.NEGATIVE_ARG, "count"), args, LogLevel.MessageClientOnly); + return; + } var target = Buffs.ParseTarget(args, 3); if (target.failMessage != null) { @@ -380,7 +399,7 @@ private static void CCRandomItemsTiered(ConCommandArgs args) { target.devotionController.UpdateAllMinions(false); } - Log.MessageNetworked($"Generated {iCount} items for {target.name}!", args); + Log.MessageNetworked($"Generated {iCount} {getItemTypeName(type)}items for {target.name}!", args); } else { @@ -922,7 +941,7 @@ private static ItemType ParseItemType(ConCommandArgs args, int index) return ItemType.Permanent; } - private static CommandTarget ParseTarget(ConCommandArgs args, int index) + public static CommandTarget ParseTarget(ConCommandArgs args, int index) { string failMessage = null; Inventory inventory = null; @@ -1000,7 +1019,7 @@ private static CommandTarget ParseTarget(ConCommandArgs args, int index) { inventory = target.inventory; var player = target.playerCharacterMasterController?.networkUser; - targetName = player?.masterController.GetDisplayName() ?? target.gameObject.name; + targetName = target.bodyInstanceObject ? RoR2.Util.GetBestBodyName(target.bodyInstanceObject) : player?.masterController.GetDisplayName() ?? target.gameObject.name; } } } @@ -1041,7 +1060,7 @@ private static BasicPickupDropTable ParseDroptable(ConCommandArgs args, int inde { droptable.selector.Clear(); droptable.canDropBeReplaced = canDropBeReplaced; - if (args.Count < index + 1 || args[index] == Lang.DEFAULT_VALUE || args[index].ToUpperInvariant() == Lang.ALL) + if (args.Count < index + 1 || args[index] == Lang.DEFAULT_VALUE) { droptable.Add(availableDropLists[ItemTier.Tier1], 1f); droptable.Add(availableDropLists[ItemTier.Tier2], 1f); diff --git a/Code/DT-Commands/Macros.cs b/Code/DT-Commands/Macros.cs index e1e3d4d..9e87289 100644 --- a/Code/DT-Commands/Macros.cs +++ b/Code/DT-Commands/Macros.cs @@ -37,6 +37,17 @@ private static void LateGame(ConCommandArgs args) Invoke(a, "set_scene", "bazaar"); } + //Is there any conflict in having it be the same convar as vanilla indev builds? + [ConCommand(commandName = "peace", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.MACRO_DTPEACE_HELP)] + [ConCommand(commandName = "dtpeace", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.MACRO_DTPEACE_HELP)] + private static void Peace(ConCommandArgs args) + { + Invoke(args.sender, "kill_all", "2", "1"); + Invoke(args.sender, "kill_all", "4", "1"); + Invoke(args.sender, "no_enemies", "1"); + //Vanilla peace also sets god 1 but ehh idk i dont need that + } + [ConCommand(commandName = "dtzoom", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.MACRO_DTZOOM_HELP)] private static void Zoom(ConCommandArgs args) { diff --git a/Code/DT-Commands/Miscellaneous.cs b/Code/DT-Commands/Miscellaneous.cs index ad78805..2b12726 100644 --- a/Code/DT-Commands/Miscellaneous.cs +++ b/Code/DT-Commands/Miscellaneous.cs @@ -2,6 +2,7 @@ using RoR2; using System.Collections; using UnityEngine; +using UnityEngine.UIElements; namespace DebugToolkit.Commands { @@ -80,27 +81,48 @@ static IEnumerator InvokeRoutine(System.Action action, float delay) } } + public static float prevTimeScale = 0; + [ConCommand(commandName = "toggle_time", flags = ConVarFlags.None, helpText = Lang.TOGGLETIME_HELP)] + private static void CC_TogglePause(ConCommandArgs args) + { + float newTimeScale = prevTimeScale; + prevTimeScale = Time.timeScale; + Time.timeScale = newTimeScale; + TimescaleNet.Invoke(newTimeScale); + } - [ConCommand(commandName = "list_mods", flags = ConVarFlags.None, helpText = "List installed mod names to get them for compatibility." + Lang.LISTMODS_ARGS)] + [ConCommand(commandName = "list_mods", flags = ConVarFlags.None, helpText = "Lists installed mod names to get them for compatibility, then lists all mods tagged as required by all")] [AutoComplete(Lang.LISTMODS_ARGS)] public static void CCMods(ConCommandArgs args) { - bool requiredByAll = args.TryGetArgBool(0).GetValueOrDefault(false); + int requiredByAll = args.TryGetArgInt(0).GetValueOrDefault(0); + UnityEngine.Debug.Log(requiredByAll); string log = string.Empty; - if (requiredByAll) + if (requiredByAll == 0 || requiredByAll == 1) { - log = "All RequiredByAllTaggedMods\n\n"; - foreach (var a in NetworkModCompatibilityHelper._networkModList) + log += "All loaded mods\n\n"; + foreach (var a in BepInEx.Bootstrap.Chainloader.PluginInfos) { log += a.ToString() + "\n"; - } + } } - else + if (requiredByAll == 0) { - log = "All loaded mods\n\n"; - foreach (var a in BepInEx.Bootstrap.Chainloader.PluginInfos) + log += "\n"; + } + if (requiredByAll == 0 || requiredByAll == 2) + { + if (NetworkModCompatibilityHelper._networkModList.Length == 0) { - log += a.ToString() + "\n"; + log += "No mods tagged as RequiredByAll. This mod pack is Vanilla compatible."; + } + else + { + log += "Mods tagged as RequiredByAll\n\n"; + foreach (var a in NetworkModCompatibilityHelper._networkModList) + { + log += a.ToString() + "\n"; + } } } Debug.Log(log); diff --git a/Code/DT-Commands/Money.cs b/Code/DT-Commands/Money.cs index 61e0e2c..3b73c28 100644 --- a/Code/DT-Commands/Money.cs +++ b/Code/DT-Commands/Money.cs @@ -175,14 +175,20 @@ public static void CC_poor(ConCommandArgs args) if (rich) { player.master.GiveMoney(2000000000 - player.master.money); - Log.MessageNetworked("We're rich", args); } else { player.master.money = 0; - Log.MessageNetworked("We're poor", args); } } + if (rich) + { + Log.MessageNetworked("We're rich", args); + } + else + { + Log.MessageNetworked("We're poor", args); + } } } diff --git a/Code/DT-Commands/PlayerCommands.cs b/Code/DT-Commands/PlayerCommands.cs index b831235..d586755 100644 --- a/Code/DT-Commands/PlayerCommands.cs +++ b/Code/DT-Commands/PlayerCommands.cs @@ -298,7 +298,7 @@ private static void CCSpawnAs(ConCommandArgs args) } else { - Log.MessageNetworked(args.sender.userName + " is spawning as " + newBody.name + " for the current stage.", args); + Log.MessageNetworked(args.sender.userName + " is spawning as " + newBody.name + " temporarily.", args); } if (!master.GetBody()) @@ -371,6 +371,12 @@ private static void CCHurt(ConCommandArgs args) Log.MessageNetworked(Lang.INSUFFICIENT_ARGS + Lang.HURT_ARGS, args, LogLevel.MessageClientOnly); return; } + bool bypassCalc = false; + if (args.Count > 2 && args[2] != Lang.DEFAULT_VALUE && !Util.TryParseBool(args[2], out bypassCalc)) + { + Log.MessageNetworked(String.Format(Lang.PARSE_ERROR, "bypassCalc", "int or bool"), args, LogLevel.MessageClientOnly); + return; + } var target = Buffs.ParseTarget(args, 1); if (target.failMessage != null) { @@ -396,6 +402,7 @@ private static void CCHurt(ConCommandArgs args) { damage = amount, position = target.body.corePosition, + damageType = bypassCalc ? DamageTypeExtended.BypassDamageCalculations : DamageTypeExtended.Generic }); Log.MessageNetworked($"Damaged {target.name} for {amount} hp.", args); } @@ -800,6 +807,11 @@ public static void CC_Skill(ConCommandArgs args) } + [ConCommand(commandName = "skin", flags = ConVarFlags.ExecuteOnServer, helpText = "[skin_variant]\nSets the skin variant for the sender's user profile.")] + public static void CC_SKIN(ConCommandArgs args) + { + Macros.Invoke(args.sender, "loadout_set_skin_variant", "self", args.TryGetArgInt(0).GetValueOrDefault(-1).ToString()); + } [ConCommand(commandName = "unlimited_junk", flags = ConVarFlags.ExecuteOnServer, helpText = "Toggle junk_unlimited. Makes skillchecks ingore junk cost.")] @@ -816,23 +828,31 @@ public static void CC_JunkAlt(ConCommandArgs args) } - - public static bool NoCooldowns = false; - [ConCommand(commandName = "nocooldown", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.LOADOUTSKIN_HELP)] - [ConCommand(commandName = "nocooldowns", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.LOADOUTSKIN_HELP)] + + [ConCommand(commandName = "nocooldown", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.NOCOOLDOWN_HELP)] + [ConCommand(commandName = "nocooldowns", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.NOCOOLDOWN_HELP)] + [AutoComplete(Lang.TARGET_PLAYER_PINGED)] public static void CC_Cooldown(ConCommandArgs args) { - if (!args.senderBody) + var target = Buffs.ParseTarget(args, 0); + if (target.failMessage != null) { + Log.MessageNetworked(target.failMessage, args, LogLevel.MessageClientOnly); + return; + } + if (!target.body) + { + Log.MessageNetworked("No target body found", args, LogLevel.MessageClientOnly); return; } - NoCooldowns = !NoCooldowns; - GenericSkill[] slots = args.senderBody.GetComponents(); + bool NoCooldowns = false; + GenericSkill[] slots = target.body.GetComponents(); foreach (GenericSkill slot in slots) { - if (NoCooldowns == true) + if (slot.skillDef.baseRechargeInterval != 0 && slot.cooldownOverride == 0) { + NoCooldowns = true; slot.cooldownOverride = 0.001f; } else @@ -840,13 +860,15 @@ public static void CC_Cooldown(ConCommandArgs args) slot.cooldownOverride = 0; } } - Log.MessageNetworked(String.Format(NoCooldowns ? Lang.SETTING_ENABLED : Lang.SETTING_DISABLED, "No Skill Cooldowns"), args); + string enable = NoCooldowns ? "Reenabled" : "Disabled"; + Log.MessageNetworked($"{NoCooldowns} Skill Cooldowns for {RoR2.Util.GetBestBodyName(target.body.gameObject)}", args); } - + //Idk what to do with this because like technically this does affect gameplay by turning off your hurtboxes and junk [ConCommand(commandName = "invis", flags = ConVarFlags.None, helpText = "Turn off your model for screenshots")] [ConCommand(commandName = "model", flags = ConVarFlags.None, helpText = "Turn off your model for screenshots")] + [ConCommand(commandName = "hide_model", flags = ConVarFlags.None, helpText = "Turn off your model for screenshots")] public static void CC_TurnOffModel(ConCommandArgs args) { @@ -866,6 +888,191 @@ public static void CC_ToggleHUD(ConCommandArgs args) } + [ConCommand(commandName = "reset_stats", flags = ConVarFlags.SenderMustBeServer, helpText = Lang.RESETSTAT_HELP)] + [AutoComplete(Lang.TARGET_PLAYER_PINGED)] + public static void CC_ReSetStats(ConCommandArgs args) + { + args.userArgs.Insert(0,""); + CC_SetStats(args); + } + + //Idk how these work with client to server + //I think they just, don't. + [ConCommand(commandName = "set_damage", flags = ConVarFlags.SenderMustBeServer, helpText = Lang.SETSTAT_HELP)] + [ConCommand(commandName = "set_attackspeed", flags = ConVarFlags.SenderMustBeServer, helpText = Lang.SETSTAT_HELP)] + [ConCommand(commandName = "set_health", flags = ConVarFlags.SenderMustBeServer, helpText = Lang.SETSTAT_HELP)] + [ConCommand(commandName = "set_regen", flags = ConVarFlags.SenderMustBeServer, helpText = Lang.SETSTAT_HELP)] + [ConCommand(commandName = "set_armor", flags = ConVarFlags.SenderMustBeServer, helpText = Lang.SETSTAT_HELP)] + [ConCommand(commandName = "set_movespeed", flags = ConVarFlags.SenderMustBeServer, helpText = Lang.SETSTAT_HELP)] + [ConCommand(commandName = "set_jumppower", flags = ConVarFlags.SenderMustBeServer, helpText = Lang.SETSTAT_HELP)] + [AutoComplete(Lang.SETSTATS_ARGS)] + public static void CC_SetStats(ConCommandArgs args) + { + if (!Run.instance) + { + Log.MessageNetworked(Lang.NOTINARUN_ERROR, args, LogLevel.MessageClientOnly); + return; + } + if (args.Count == 0 || (args.sender == null && (args.Count < 2 || args[1] == Lang.DEFAULT_VALUE))) + { + Log.MessageNetworked(Lang.INSUFFICIENT_ARGS + Lang.SETSTATS_ARGS, args, LogLevel.MessageClientOnly); + return; + } + var target = Buffs.ParseTarget(args, 1); + if (target.failMessage != null) + { + Log.MessageNetworked(target.failMessage, args, LogLevel.MessageClientOnly); + return; + } + if (!target.body) + { + Log.MessageNetworked("No target body found", args, LogLevel.MessageClientOnly); + return; + } + if (!TextSerialization.TryParseInvariant(args[0], out float amount)) + { + Log.MessageNetworked(string.Format(Lang.PARSE_ERROR, "amount", "float"), args, LogLevel.MessageClientOnly); + return; + } + + Stat statToSet = Stat.Reset; + string command = args.commandName; + + switch (command) + { + case "set_damage": + statToSet = Stat.Damage; + break; + case "set_attackspeed": + statToSet = Stat.AttackSpeed; + break; + case "set_health": + statToSet = Stat.MaxHealth; + break; + case "set_regen": + statToSet = Stat.Regen; + break; + case "set_armor": + statToSet = Stat.Armor; + break; + case "set_movespeed": + statToSet = Stat.MoveSpeed; + break; + case "set_jumppower": + statToSet = Stat.JumpPower; + break; + case "reset_stats": + statToSet = Stat.Reset; + break; + } + SetStatsForBody(target.body, statToSet, amount); + if (statToSet == Stat.Reset) + { + Log.MessageNetworked($"Reset {target.name}'s stats to their base values.", args); + } + else + { + Log.MessageNetworked($"Set {target.name}'s {statToSet} to {amount}.", args); + } + + + } + + public enum Stat + { + + Damage, + AttackSpeed, + MaxHealth, + Regen, + Armor, + MoveSpeed, + JumpPower, + + Reset, + } + public static void SetStatsForBody(CharacterBody body, Stat stat, float amount) + { + var ogBody = body.master.bodyPrefab.GetComponent(); + switch (stat) + { + + case Stat.Damage: + body.baseDamage = amount; + body.levelDamage = 0; + break; + case Stat.AttackSpeed: + body.baseAttackSpeed = amount; + body.levelAttackSpeed = 0; + break; + case Stat.MaxHealth: + body.baseMaxHealth = amount; + body.levelMaxHealth = 0; + break; + case Stat.Regen: + body.baseRegen = amount; + body.levelRegen = 0; + break; + case Stat.Armor: + body.baseArmor = amount; + body.levelArmor = 0; + break; + case Stat.MoveSpeed: + body.baseMoveSpeed = amount; + body.levelMoveSpeed = 0; + body.baseAcceleration = (ogBody.baseAcceleration * (amount / ogBody.baseMoveSpeed)); + break; + case Stat.JumpPower: + body.baseJumpPower = amount; + body.levelJumpPower = 0; + break; + case Stat.Reset: + body.baseDamage = ogBody.baseDamage; + body.levelDamage = ogBody.levelDamage; + body.baseAttackSpeed = ogBody.baseAttackSpeed; + body.levelAttackSpeed = ogBody.levelAttackSpeed; + // + body.baseMaxHealth = ogBody.baseMaxHealth; + body.levelMaxHealth = ogBody.levelMaxHealth; + body.baseRegen = ogBody.baseRegen; + body.levelRegen = ogBody.levelRegen; + body.baseArmor = ogBody.baseArmor; + body.levelArmor = ogBody.levelArmor; + // + body.baseMoveSpeed = ogBody.baseMoveSpeed; + body.levelMoveSpeed = ogBody.levelMoveSpeed; + body.baseAcceleration = ogBody.baseAcceleration; + body.level = ogBody.levelMoveSpeed; + body.baseJumpPower = ogBody.baseJumpPower; + body.levelJumpPower = ogBody.levelJumpPower; + break; + } + body.MarkAllStatsDirty(); + } + + [ConCommand(commandName = "set_health", flags = ConVarFlags.ExecuteOnServer, helpText = "Sets health to specifiedd amount and removes regen for testing.")] + public static void CC_SetHP(ConCommandArgs args) + { + if (!args.senderMaster) + { + return; + } + if (!args.senderMaster.GetBody()) + { + //WolfoLib.log.LogMessage("No Body"); + return; + } + float newDamage = (float)System.Convert.ToInt16(args[0]); + var body = args.senderMaster.GetBody(); + body.baseMaxHealth = newDamage; + body.levelMaxHealth = 0; + body.maxHealth = newDamage; + body.baseRegen = 0; + body.levelRegen = 0; + body.regen = 0; + + body.healthComponent.health = body.maxHealth; + } } diff --git a/Code/Hooks.cs b/Code/Hooks.cs index c16c367..b4cc86b 100644 --- a/Code/Hooks.cs +++ b/Code/Hooks.cs @@ -160,7 +160,7 @@ private static void SetBuddhaMode(On.RoR2.CharacterBody.orig_Start orig, Charact { self.bodyFlags |= CharacterBody.BodyFlags.Buddha; } - if (PlayerCommands.NoCooldowns) + /*if (PlayerCommands.NoCooldowns) { GenericSkill[] slots = self.GetComponents(); foreach (GenericSkill slot in slots) @@ -170,7 +170,7 @@ private static void SetBuddhaMode(On.RoR2.CharacterBody.orig_Start orig, Charact slot.cooldownOverride = 0.001f; } } - } + }*/ } else if(buddhaMonsters) { @@ -392,9 +392,10 @@ void ExpandHelpText(BaseConVar cv, string text) RemoveCheatFlag(self.FindConVar("bag_disable_breakout")); RemoveCheatFlag(self.FindConVar("bounce_velocity")); RemoveCheatFlag(self.FindConVar("junk_unlimited")); + RemoveCheatFlag(self.FindConVar("timescale")); const string MOD_MESSAGE = " Let the DebugToolkit team know if you need this convar."; - ExpandHelpText(self.FindConVar("timescale"), " Use time_scale instead!"); + //ExpandHelpText(self.FindConVar("timescale"), " Use time_scale instead!"); ExpandHelpText(self.FindConVar("director_combat_disable"), " Use no_enemies instead!"); ExpandHelpText(self.FindConVar("timestep"), MOD_MESSAGE); ExpandHelpText(self.FindConVar("cmotor_safe_collision_step_threshold"), MOD_MESSAGE); diff --git a/Code/Lang.cs b/Code/Lang.cs index 4f61033..9863506 100644 --- a/Code/Lang.cs +++ b/Code/Lang.cs @@ -12,7 +12,7 @@ public const string BIND_DELETE_ARGS = "Requires 1 argument: {key}", CHANGETEAM_ARGS = "Requires 1 (2 if from server) argument: {team} [player:]", CHARGEZONE_ARGS = "Requires 1 argument: {charge}", - CREATEPICKUP_ARGS = "Requires 1 (3 if from server) argument: {object (item|equip|drone|'lunarcoin'|'voidcoin')} [search ('item'|'equip'|'drone'|'all'|'pickup'):'all'] [type ('permanent'|'temp'):'permanent'] player:]", + CREATEPICKUP_ARGS = "Requires 1 (3 if from server) argument: {object (item|equip|drone|'lunarcoin'|'voidcoin')} [search ('item'|'equip'|'drone'|'all'|'pickup'):'all'] [itemTypesNoChanneled:'permanent'] player:]", CREATEPOTENTIAL_ARGS = "Requires 0 (3 if from server) arguments: [droptable (droptable|'all'):'all'] [count:3] *[player:]", DELAY_ARGS = "Requires 2 arguments: {delay} {console_commands}", DUMPSTATE_ARGS = "Requires 0 (1 if from server) argument: [target (player|'pinged'):]", @@ -26,17 +26,19 @@ public const string RANDOMEQUIP_ARGS = "Requires 0 (1 if from server) argument: [target (player|'pinged'):]", //GIVEITEM_ARGS = "Requires 1 (3 if from server) argument: {item} [count:1] [type ('permanent'|'temp'|'channeled'):'permanent'] [target (player|'pinged'|'evolution'|'simulacrum'|'voidfields'|'devotion'):]", GIVEITEM_ARGS = "Requires 1 (3 if from server) argument: {item} [count:1] [itemTypes:'permanent'] [target (player|'pinged'|'evolution'|'simulacrum'|'voidfields'|'devotion'):]", - GIVEDRONE_ARGS = "Requires 1 (2 if from server) argument: {drone} [count:1] [tier:1] [target (player|'pinged'):]", + GIVEDRONE_ARGS = "Requires 1 (2 if from server) argument: {drone} [count:1] [droneTier:1] [target (player|'pinged'):]", GIVELUNAR_ARGS = "Requires 0 arguments: [amount:1]", GIVEMONEY_ARGS = "Requires 1 argument: {amount} [target (player|'all')]", MONEY_ARGS = "Requires 0 argument: [target (player|'all')]", + SETSTATS_ARGS = "Requires 1 argument: {amount} [target (player|'pinged'):]", + TARGET_PLAYER_PINGED = "Requires 0 argument: [target (player|'pinged'):]", HEAL_ARGS = "Requires 1 argument: {amount} [target (player|'pinged'):]", - HURT_ARGS = "Requires 1 argument: {amount} [target (player|'pinged'):]", + HURT_ARGS = "Requires 1 argument: {amount} [target (player|'pinged'):] [bypassCalcs (0|1):0/false]", KICK_ARGS = "Requires 1 argument: {player}", - KILLALL_ARGS = "Requires 0 arguments: [team:Monster]", + KILLALL_ARGS = "Requires 0 arguments: [team:Monster&Void], [trueKill (0|1):0/false]", LISTSKIN_ARGS = "Requires 0 arguments: [selection (body|'all'|'body'|'self'):'all']", LISTQUERY_ARGS = "Requires 0 arguments: [query]", - LISTMODS_ARGS = "Requires 0 arguments: [filterByRequiredByAll (0|1):0/false]", + LISTMODS_ARGS = "Requires 0 arguments: [filterByRequiredByAll (0'both'|1'yes'|2'no'):0]", LOADOUTSKIN_ARGS = "Requires 2 argument: {body_name (body|'self')} {skin_index}", LOADOUTSKILL_ARGS = "Requires 2 argument: {skill_slot} {skill_variant}", NEXTBOSS_ARGS = "Requires 1 argument: {director_card} [count:1] [elite:None]", @@ -44,7 +46,7 @@ public const string NO_ARGS = "Requires 0 arguments.", PERM_MOD_ARGS = "Requires 2 arguments: {permission_level} {player}", POSTSOUNDEVENT_ARGS = "Requires 1 argument: {sound_event (event_name|event_id)}", - RANDOMITEM_ARGS = "Requires 1 (3 if from server) argument: {count} [tier (tier|'all'):'\"0,1,2,4\"'] [type ('permanent'|'temp'):'permanent'] [target (player|'pinged'|'evolution'|'simulacrum'|'voidfields'|'devotion'):]", + RANDOMITEM_ARGS = "Requires 1 (3 if from server) argument: {count} [tier (tier|'all'):'\"0,1,2,4\"'] [itemTypes:'permanent'] [target (player|'pinged'|'evolution'|'simulacrum'|'voidfields'|'devotion'):]", RANDOMITEM2_ARGS = "Requires 1 (3 if from server) argument: {count} [allowLunar (0|1):0/false] [allowVoid (0|1):0/false] [target (player|'pinged'|'evolution'|'simulacrum'|'voidfields'|'devotion'):]", REMOVEALLBUFFS_ARGS = "Requires 0 (2 if from server) arguments: [timed (0|1):0/false] [target (player|'pinged'):]", REMOVEALLDOTS_ARGS = "Requires 0 (1 if from server) arguments: [target (player|'pinged'):]", @@ -99,12 +101,17 @@ public const string RANDOMEQUIP_HELP = "Gives a random equipment to a target. " + RANDOMEQUIP_ARGS, GIVEITEM_HELP = "Gives the specified item to a target. " + GIVEITEM_ARGS, GIVEDRONE_HELP = "Summons the specified drone to a target. " + GIVEDRONE_ARGS, + REMOVEALLDRONES_HELP = "Removes all drones from the target. " + KICK_ARGS, + KILL_ALL_MINIONS_HELP = "Kills all minions owned by target. " + KICK_ARGS, GIVELUNAR_HELP = "Gives amount of lunar coin to you. " + GIVELUNAR_ARGS, GIVEVOID_HELP = "Gives amount of void markers to you. " + GIVELUNAR_ARGS, GIVEMONEY_HELP = "Gives the specified amount of money to the specified player. " + GIVEMONEY_ARGS, NO_MONEY_HELP = "Sets money to 0 for specified player. " + GIVEMONEY_ARGS, ALLMONEY_HELP = "Sets money to 2'000'000'000 for specified player. " + GIVEMONEY_ARGS, GOD_HELP = "Become invincible. " + ENABLE_ARGS, + SETSTAT_HELP = "Sets the base stat to a specific value for yourself or target, and the level stat to 0. " + SETSTATS_ARGS, + RESETSTAT_HELP = "Resets the base & level stats for yourself or target", + HEAL_HELP = "Heal yourself or another target. " + HEAL_ARGS, HURT_HELP = "Deal generic damage to yourself or another target. " + HURT_ARGS, KICK_HELP = "Kicks the specified player from the session. " + KICK_ARGS, @@ -129,7 +136,8 @@ public const string LISTTEAM_HELP = "List all Teams and their language invariants. " + LISTQUERY_ARGS, LOADOUTSKIN_HELP = "Change your loadout's skin. " + LOADOUTSKIN_ARGS, LOCKEXP_HELP = "Prevent Experience gain. " + ENABLE_ARGS, - NOCOOLDOWN_HELP = "Toggles your Skill Cooldowns", + NOCOOLDOWN_HELP = "Toggles skill cooldowns of the target. " + TARGET_PLAYER_PINGED, + MACRO_DTPEACE_HELP = "Kills all enemies, voids and disables enemies spawning.", MACRO_DTZOOM_HELP = "Gives you 20 hooves and 200 feathers for getting around quickly.", MACRO_DTDAMAGE_HELP = "Gives you a lot of BoostDamage hidden item.", MACRO_SCANNER_HELP = "Gives you 100 boostEquipmentRecharge and the Radar Scanner equipment to easily search stages.", @@ -171,7 +179,8 @@ public const string SPAWNPORTAL_HELP = "Spawns a portal in front of the player. " + SPAWNPORTAL_ARGS, STOPTIMER_HELP = "Pause/unpause the run timer. " + ENABLE_ARGS, TIMESCALE_HELP = "Sets the Time Delta. " + TIMESCALE_ARGS, - TRUEKILL_HELP = "Ignore Dio's and God and kill the entity. " + TRUEKILL_ARGS + TRUEKILL_HELP = "Kill the entity bypassing revives, buddha & godmode . " + TRUEKILL_ARGS, + TOGGLETIME_HELP = "Toggles timescale between 0 and normal value. " ; // Messages @@ -184,8 +193,11 @@ public const string CREATEPICKUP_SUCCESS_2 = "Successfully created a potential with {0} options.", GIVELUNAR_2 = "{0} {1} lunar coin(s).", GIVEVOIDC_2 = "{0} {1} void marker(s).", - GIVEOBJECT = "Gave {0} {3} {1} to {2}.", + GIVEITEM = "Gave {0} {1} to {2}.", //Amount ItemType Item Target + GIVEBUFF = "Gave {0} {1} to {2}.", GIVEDRONE = "Summoned {0} {1} (Tier {3}) to {2}.", + REMOVEDRONES = "Removed {0} drones from {1}.", + Kill_MINIONS = "Killed all minions owned by {0}.", OBSOLETEWARNING = "This command has become obsolete and will be removed in the next version. ", NETWORKING_OTHERPLAYER_4 = "{0}({1}) issued: {2} {3}", NOMESSAGE = "Yell at the modmakers if you see this message!", @@ -194,8 +206,11 @@ public const string PLAYER_SKINCHANGERESPAWN = "Player will spawn with the specified skin next round. " + USE_RESPAWN, REMOVEOBJECT = "Removed {0} {1} from {2}.", RUNSETSTAGESCLEARED_HELP = "Sets the amount of stages cleared. This does not change the current stage.", + TEMP = "{0} temporary", SETTING_ENABLED = "{0} enabled", SETTING_DISABLED = "{0} disabled", + SETTING_ENABLED2 = "Enabled", + SETTING_DISABLED2 = "Disabled", SPAWN_ATTEMPT_1 = "Attempting to spawn: {0}", SPAWN_ATTEMPT_2 = "Attempting to spawn {0}: {1}", USE_RESPAWN = "Use 'respawn' to skip the wait." diff --git a/DebugToolkit.csproj b/DebugToolkit.csproj index 0cb2604..728884c 100644 --- a/DebugToolkit.csproj +++ b/DebugToolkit.csproj @@ -89,7 +89,7 @@ - + From ecc3766af85a8bf0494e1f5e35902a0fc1432263 Mon Sep 17 00:00:00 2001 From: Wolfo Date: Tue, 30 Dec 2025 22:54:41 +0100 Subject: [PATCH 03/25] send it --- CHANGELOG.md | 4 +++- Code/DT-Commands/PlayerCommands.cs | 4 ++-- Code/StringFinder.cs | 33 +++++++++++++++++++++++++++--- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3998420..02bb9f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,7 +50,7 @@ * 'give_buff' now works with negative amount for removing. * 'loadout_set_skill_variant' now accepts 'self' * 'random_items' changed default value to not give Lunars & Voids. - * 'hurt' second optional argument to bypass armor/damage calculations. + * 'hurt' third optional argument to bypass armor&damage calculations. * 'kill_all' no value given now kills Monster & Void teams. * 'kill_all' second optional argument to bypass revives. (Does not bypass Godmode) * 'true_kill' now bypasses godmode. @@ -59,6 +59,8 @@ * Amount of spawned interactables/monsters/drones by commands capped at a 100 per command, to not crash the game if you mistype. * Fixed 'god 0/1'/'buddha 0/1' not setting the toggle's state. * Fixed 'loadout_set_skin_variant' crashing the game. + * Modded interactables should be spawnable from the start now. + ### 3.21 ### * **3.21.1** diff --git a/Code/DT-Commands/PlayerCommands.cs b/Code/DT-Commands/PlayerCommands.cs index d586755..fc93906 100644 --- a/Code/DT-Commands/PlayerCommands.cs +++ b/Code/DT-Commands/PlayerCommands.cs @@ -860,8 +860,8 @@ public static void CC_Cooldown(ConCommandArgs args) slot.cooldownOverride = 0; } } - string enable = NoCooldowns ? "Reenabled" : "Disabled"; - Log.MessageNetworked($"{NoCooldowns} Skill Cooldowns for {RoR2.Util.GetBestBodyName(target.body.gameObject)}", args); + string enable = NoCooldowns ? "Disabled" : "Reenabled"; + Log.MessageNetworked($"{enable} Skill Cooldowns for {RoR2.Util.GetBestBodyName(target.body.gameObject)}", args); } diff --git a/Code/StringFinder.cs b/Code/StringFinder.cs index 6cce321..e3afe78 100644 --- a/Code/StringFinder.cs +++ b/Code/StringFinder.cs @@ -6,6 +6,7 @@ using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.ResourceManagement.AsyncOperations; +using UnityEngine.UI; namespace DebugToolkit { @@ -54,13 +55,39 @@ private static void GatherCSCs() private void GatherISCs() { - GatherAddressableAssets("/isc", (asset) => interactableSpawnCards.Add(asset)); - On.RoR2.ClassicStageInfo.Start += AddCurrentStageIscsToCache; + //GatherAddressableAssets("/isc", (asset) => interactableSpawnCards.Add(asset)); + //On.RoR2.ClassicStageInfo.Start += AddCurrentStageIscsToCache; + + RoR2Application.onLoad += () => + { + //Doing this first means only getting loaded spawn cards. + //Which for vanilla isn't a lot of them (38) + //But itll find any modded ones and mod-edited ones. + var ISCList = Resources.FindObjectsOfTypeAll(typeof(InteractableSpawnCard)) as InteractableSpawnCard[]; + + //Unless there's some issue with WaitForFinished() + //Gotta do it this way to get vanillaInteractables first then moddedInteractables, without jumbling up the order + foreach (var resourceLocator in Addressables.ResourceLocators) + { + foreach (var key in resourceLocator.Keys) + { + var keyString = key.ToString(); + if (keyString.Contains("/isc")) + { + interactableSpawnCards.Add(Addressables.LoadAssetAsync(keyString).WaitForCompletion()); + } + } + } + + var filteredList = + ISCList.Where(spawnCard => spawnCard is InteractableSpawnCard && interactableSpawnCards.All(existingIsc => existingIsc.name != spawnCard.name)); + interactableSpawnCards.AddRange(filteredList); + }; } private static void GatherAddressableAssets(string filterKey, Action onAssetLoaded) { - RoR2Application.onLoad += () => + RoR2Application.onLoadFinished += () => { foreach (var resourceLocator in Addressables.ResourceLocators) { From 3de7716e8a539755a9c36a10c0c35a4896d0b480 Mon Sep 17 00:00:00 2001 From: Wolfo Date: Tue, 30 Dec 2025 23:01:04 +0100 Subject: [PATCH 04/25] Update Lang.cs --- Code/Lang.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Lang.cs b/Code/Lang.cs index 9863506..fafad32 100644 --- a/Code/Lang.cs +++ b/Code/Lang.cs @@ -62,7 +62,7 @@ public const string RUNSETWAVESCLEARED_ARGS = "Requires 1 argument {wave}", SEED_ARGS = "Requires 0 or 1 argument: [new_seed]", SETARTIFACT_ARGS = "Requires 1 (2 if using 'all') argument: {artifact (artifact|'all')} [enable (0|1)]", - SPAWNAI_ARGS = "Requires 1 argument: {ai} [count:1] [elite:None] [braindead (0|1):0/false] [team:Monster]", + SPAWNAI_ARGS = "Requires 1 argument: {ai} [count:1] [elite:None] [braindead (0|1):0/false] [team (team|'ally'):Monster]", SPAWNAS_ARGS = "Requires 1 (3 if from server) argument: {body} [permanent (0|1):0/false] [player:]", SPAWNBODY_ARGS = "Requires 1 argument: {body}", SPAWNINTERACTABLE_ARGS = "Requires 1 argument: {interactable} [count:1]", From 095edf48e0ef135bc82f7cbe872f89a4cfb07f77 Mon Sep 17 00:00:00 2001 From: Wolfo Date: Wed, 31 Dec 2025 13:43:02 +0100 Subject: [PATCH 05/25] set_crit & spawn_as permament1 default --- CHANGELOG.md | 2 +- Code/DT-Commands/PlayerCommands.cs | 14 +++++++++++--- Code/Lang.cs | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02bb9f3..f727dec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ * 'kill_minions': Kills all minions, leaving dead drones. * 'list_drone': List drone names and ids. - * 'set_ .. damage, attackspeed, health, regen, armor, movespeed' Sets the stat to the specified value, for the target, for that life; For clean testing. + * 'set_ .. damage, attackspeed, crit, health, regen, armor, movespeed' Sets the stat to the specified value, for the target, for that life; For clean testing. * 'reset_stats' Undoes changes from 'set_..' commands. * 'nocooldowns': disables your skill cooldowns diff --git a/Code/DT-Commands/PlayerCommands.cs b/Code/DT-Commands/PlayerCommands.cs index fc93906..58b22b2 100644 --- a/Code/DT-Commands/PlayerCommands.cs +++ b/Code/DT-Commands/PlayerCommands.cs @@ -291,7 +291,7 @@ private static void CCSpawnAs(ConCommandArgs args) } master.bodyPrefab = newBody; - if (args.TryGetArgBool(1).GetValueOrDefault(false)) + if (args.TryGetArgBool(1).GetValueOrDefault(true)) { master.originalBodyPrefab = newBody; Log.MessageNetworked(args.sender.userName + " is spawning as " + newBody.name + " for the rest of the run.", args); @@ -889,6 +889,7 @@ public static void CC_ToggleHUD(ConCommandArgs args) [ConCommand(commandName = "reset_stats", flags = ConVarFlags.SenderMustBeServer, helpText = Lang.RESETSTAT_HELP)] + [ConCommand(commandName = "unset_stats", flags = ConVarFlags.SenderMustBeServer, helpText = Lang.RESETSTAT_HELP)] [AutoComplete(Lang.TARGET_PLAYER_PINGED)] public static void CC_ReSetStats(ConCommandArgs args) { @@ -900,6 +901,7 @@ public static void CC_ReSetStats(ConCommandArgs args) //I think they just, don't. [ConCommand(commandName = "set_damage", flags = ConVarFlags.SenderMustBeServer, helpText = Lang.SETSTAT_HELP)] [ConCommand(commandName = "set_attackspeed", flags = ConVarFlags.SenderMustBeServer, helpText = Lang.SETSTAT_HELP)] + [ConCommand(commandName = "set_crit", flags = ConVarFlags.SenderMustBeServer, helpText = Lang.SETSTAT_HELP)] [ConCommand(commandName = "set_health", flags = ConVarFlags.SenderMustBeServer, helpText = Lang.SETSTAT_HELP)] [ConCommand(commandName = "set_regen", flags = ConVarFlags.SenderMustBeServer, helpText = Lang.SETSTAT_HELP)] [ConCommand(commandName = "set_armor", flags = ConVarFlags.SenderMustBeServer, helpText = Lang.SETSTAT_HELP)] @@ -946,6 +948,9 @@ public static void CC_SetStats(ConCommandArgs args) case "set_attackspeed": statToSet = Stat.AttackSpeed; break; + case "set_crit": + statToSet = Stat.Crit; + break; case "set_health": statToSet = Stat.MaxHealth; break; @@ -980,15 +985,14 @@ public static void CC_SetStats(ConCommandArgs args) public enum Stat { - Damage, AttackSpeed, + Crit, MaxHealth, Regen, Armor, MoveSpeed, JumpPower, - Reset, } public static void SetStatsForBody(CharacterBody body, Stat stat, float amount) @@ -1005,6 +1009,10 @@ public static void SetStatsForBody(CharacterBody body, Stat stat, float amount) body.baseAttackSpeed = amount; body.levelAttackSpeed = 0; break; + case Stat.Crit: + body.baseCrit = amount; + body.levelCrit = 0; + break; case Stat.MaxHealth: body.baseMaxHealth = amount; body.levelMaxHealth = 0; diff --git a/Code/Lang.cs b/Code/Lang.cs index fafad32..3390694 100644 --- a/Code/Lang.cs +++ b/Code/Lang.cs @@ -63,7 +63,7 @@ public const string SEED_ARGS = "Requires 0 or 1 argument: [new_seed]", SETARTIFACT_ARGS = "Requires 1 (2 if using 'all') argument: {artifact (artifact|'all')} [enable (0|1)]", SPAWNAI_ARGS = "Requires 1 argument: {ai} [count:1] [elite:None] [braindead (0|1):0/false] [team (team|'ally'):Monster]", - SPAWNAS_ARGS = "Requires 1 (3 if from server) argument: {body} [permanent (0|1):0/false] [player:]", + SPAWNAS_ARGS = "Requires 1 (3 if from server) argument: {body} [permanent (0|1):1/true] [player:]", SPAWNBODY_ARGS = "Requires 1 argument: {body}", SPAWNINTERACTABLE_ARGS = "Requires 1 argument: {interactable} [count:1]", SPAWNPORTAL_ARGS = "Requires 1 argument: {portal ('artifact'|'blue'|'celestial'|'deepvoid'|'gold'|'green'|'null'|'void')}", From 10914139486c09050944cc38ed746c83df5cca25 Mon Sep 17 00:00:00 2001 From: Wolfo Date: Wed, 31 Dec 2025 21:11:42 +0100 Subject: [PATCH 06/25] Cleanup 1 --- CHANGELOG.md | 22 +-- Code/AutoCompletion/AutoCompleteManager.cs | 32 ++- Code/DT-Commands/Buffs.cs | 2 +- Code/DT-Commands/CurrentRun.cs | 129 +++++++------ Code/DT-Commands/Drones.cs | 68 +++---- Code/DT-Commands/Items.cs | 173 ++++------------- Code/DT-Commands/LobbyManagement.cs | 52 +++-- Code/DT-Commands/Macros.cs | 18 +- Code/DT-Commands/Miscellaneous.cs | 55 ++---- Code/DT-Commands/Money.cs | 99 ++++------ Code/DT-Commands/PlayerCommands.cs | 215 +++++++++------------ Code/DT-Commands/Spawners.cs | 18 +- Code/DebugToolkit.cs | 1 + Code/Hooks.cs | 22 +-- Code/Lang.cs | 56 +++--- Code/StringFinder.cs | 65 ++++++- 16 files changed, 444 insertions(+), 583 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f727dec..8c7c556 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,10 @@ - -## Changelog ## ### 3.22 ### * **3.22.0** * Added commands: * 'give_drone': Summons drone, specified amount and tier * 'remove_all_drones': Removes all drones, leaving no bodies. - * 'kill_minions': Kills all minions, leaving dead drones. + * 'kill_all_minions': Kills all minions, leaving dead drones. * 'list_drone': List drone names and ids. * 'set_ .. damage, attackspeed, crit, health, regen, armor, movespeed' Sets the stat to the specified value, for the target, for that life; For clean testing. @@ -14,13 +12,14 @@ * 'nocooldowns': disables your skill cooldowns * 'list_pickups': List pickup names and ids. - * 'list_mods': Lists all loaded mods and if they are tagged as RequiredByAll. Useful to get internal names to check for. - * 'buddhaenemy', 'invulenemy': Buddha mode for all enemies, to make them unkillable. + * 'dump_mods': Lists all loaded mods and if they are tagged as RequiredByAll. Useful to get internal names to check for. + * 'godenemy': God mode for all monsters, to make them unhurtable. + * 'buddhaenemy': Buddha mode for all monsters, to make them unkillable. * 'goto_boss': Teleports you to boss, teleporter or boss arenas on stage, (so you don't have to fly to Mithrix 100 times) * 'hide_model': hides model, for screenshotting/recording. - * 'evolve_lemurian': Triggers Artifact of Devotion evolution. - * 'give_voidcoin': Gives Void Markers. + * 'evolve_lemurians': Triggers Artifact of Devotion evolution. + * 'give_void': Gives Void Markers. * 'no_interactables': Prevent interactables from spawning * 'toggle_time' Toggles 'time_scale' between 0 and what it it was before. @@ -40,10 +39,9 @@ * Updated command functionality: * Item commands can now grant/remove channeled items - * Item commands now mention you can type 1/2/3 instead of the name type. + * Item commands now mention you can type 0/1/2 instead of the name type. * 'spawn_interactable' now also shows interactable names in auto complete. * 'spawn_interactable' now accepts amount. - * 'spawn_as' now has second argument to permanently spawn as the new body. (Like prior to AC behaviour) //Default False * 'create_pickup' now supports dropping drones & pickups. * 'create_pickup' switched {search} and {permanent/temp} argument spots. * 'give_equip -1' now removes your equipment. @@ -52,14 +50,12 @@ * 'random_items' changed default value to not give Lunars & Voids. * 'hurt' third optional argument to bypass armor&damage calculations. * 'kill_all' no value given now kills Monster & Void teams. - * 'kill_all' second optional argument to bypass revives. (Does not bypass Godmode) - * 'true_kill' now bypasses godmode. + * 'true_kill' now bypasses godmode and accepts 'pinged' & 'all' as target - * Amount of spawned interactables/monsters/drones by commands capped at a 100 per command, to not crash the game if you mistype. * Fixed 'god 0/1'/'buddha 0/1' not setting the toggle's state. * Fixed 'loadout_set_skin_variant' crashing the game. - * Modded interactables should be spawnable from the start now. + * Modded spawn cards should be usable from the start now. ### 3.21 ### diff --git a/Code/AutoCompletion/AutoCompleteManager.cs b/Code/AutoCompletion/AutoCompleteManager.cs index cc065af..389f43c 100644 --- a/Code/AutoCompletion/AutoCompleteManager.cs +++ b/Code/AutoCompletion/AutoCompleteManager.cs @@ -1,4 +1,5 @@ -using RoR2; +using DebugToolkit.Commands; +using RoR2; using System; using System.Collections.Generic; using System.Linq; @@ -69,17 +70,22 @@ internal static void RegisterAutoCompleteCommands() var parser = new AutoCompleteParser(); parser.RegisterStaticVariable("0", "0"); parser.RegisterStaticVariable("1", "1"); + parser.RegisterStaticVariable("count", "count"); + parser.RegisterStaticVariable("droneTier", "droneTier"); parser.RegisterStaticVariable("ai", MasterCatalog.allAiMasters.Select(i => $"{(int)i.masterIndex}|{i.name}|{StringFinder.GetLangInvar(StringFinder.GetMasterName(i))}"), 1); parser.RegisterStaticVariable("artifact", ArtifactCatalog.artifactDefs.Select(i => $"{(int)i.artifactIndex}|{i.cachedName}|{StringFinder.GetLangInvar(i.nameToken)}"), 1); parser.RegisterStaticVariable("body", BodyCatalog.allBodyPrefabBodyBodyComponents.Select(i => $"{(int)i.bodyIndex}|{i.name}|{StringFinder.GetLangInvar(i.baseNameToken)}"), 1); parser.RegisterStaticVariable("buff", BuffCatalog.buffDefs.Select(i => $"{(int)i.buffIndex}|{StringFinder.GetLangInvar(i.name)}"), 1); - parser.RegisterStaticVariable("tier", ItemTierCatalog.allItemTierDefs.OrderBy(i => i.tier).Select(i => $"{(int)i.tier}|{i.name}"), 1); + parser.RegisterStaticVariable("droptable", ItemTierCatalog.allItemTierDefs.OrderBy(i => i.tier).Select(i => $"{(int)i.tier}|{i.name}"), 1); parser.RegisterStaticVariable("dot", DotController.dotDefs.Select((d, i) => $"{i}|{(DotController.DotIndex)i}"), 1); parser.RegisterStaticVariable("elite", new string[] { "-1|None" }. Concat(EliteCatalog.eliteDefs.Select(i => $"{(int)i.eliteIndex}|{i.name}|{StringFinder.GetLangInvar(i.modifierToken)}")), 1 ); - parser.RegisterStaticVariable("equip", EquipmentCatalog.equipmentDefs.Select(i => $"{(int)i.equipmentIndex}|{i.name}|{StringFinder.GetLangInvar(i.nameToken)}"), 1); + parser.RegisterStaticVariable("equip", new string[] { "-1|None" }. + Concat(EquipmentCatalog.equipmentDefs.Select(i => $"{(int)i.equipmentIndex}|{i.name}|{StringFinder.GetLangInvar(i.nameToken)}")), + 1 + ); parser.RegisterStaticVariable("item", ItemCatalog.allItemDefs.Select(i => $"{(int)i.itemIndex}|{i.name}|{StringFinder.GetLangInvar(i.nameToken)}"), 1); parser.RegisterStaticVariable("drone", DroneCatalog.allDroneDefs.Select(i => $"{(int)i.droneIndex}|{i.name}|{StringFinder.GetLangInvar(i.nameToken)}"), 1); parser.RegisterStaticVariable("specific_stage", SceneCatalog.allSceneDefs.Where(i => !i.isOfflineScene).Select(i => $"{(int)i.sceneDefIndex}|{i.cachedName}|{StringFinder.GetLangInvar(i.nameToken)}"), 1); @@ -90,23 +96,15 @@ internal static void RegisterAutoCompleteCommands() parser.RegisterStaticVariable("permission_level", CollectEnumNames(typeof(Permissions.Level), typeof(int)), 1); - parser.RegisterDynamicVariable("director_card", StringFinder.Instance.DirectorCards, "spawnCard", autocompleteIndex: 1); - //parser.RegisterDynamicVariable("interactable", StringFinder.Instance.InteractableSpawnCards, autocompleteIndex: 1); - parser.RegisterDynamicVariable("interactable", StringFinder.Instance.InteractableSpawnCards.Select(i => $"{StringFinder.Instance.InteractableSpawnCards.IndexOf(i)}|{i.name}|{StringFinder.GetLangInvar(i.prefab?.GetComponent()?.GetDisplayName())}"), autocompleteIndex: 1); + parser.RegisterStaticVariable("director_card", StringFinder.Instance.DirectorCards.Select(i => $"{i}|{i.GetSpawnCard().name}"), autocompleteIndex: 1); + parser.RegisterStaticVariable("interactable", StringFinder.Instance.InteractableSpawnCards.Select(i => $"{StringFinder.Instance.InteractableSpawnCards.IndexOf(i)}|{i.name}|{StringFinder.GetLangInvar(i.prefab?.GetComponent()?.GetDisplayName())}"), autocompleteIndex: 1); parser.RegisterDynamicVariable("player", NetworkUser.instancesList, "userName"); - parser.RegisterStaticVariable("itemTypes", new string[] { - "1|Permanent", - "2|Temp", - "3|Channelled", - },1 - ); - parser.RegisterStaticVariable("itemTypesNoChanneled", new string[] { - "1|Permanent", - "2|Temp", - }, 1 - ); + parser.RegisterStaticVariable("item_type", CollectEnumNames(typeof(Items.ItemType), typeof(int)), 1); + parser.RegisterStaticVariable("pickup_type", CollectEnumNames(typeof(Items.PickupType), typeof(int)), 1); + parser.RegisterStaticVariable("pickup_category", CollectEnumNames(typeof(Items.PickupCategory), typeof(int)), 1); + parser.Scan(System.Reflection.Assembly.GetExecutingAssembly()); } diff --git a/Code/DT-Commands/Buffs.cs b/Code/DT-Commands/Buffs.cs index b15616c..28f9242 100644 --- a/Code/DT-Commands/Buffs.cs +++ b/Code/DT-Commands/Buffs.cs @@ -142,7 +142,7 @@ private static void CCGiveBuff(ConCommandArgs args) body.AddBuff(buff); } } - Log.MessageNetworked(string.Format(Lang.GIVEBUFF, iCount, name, target.name, ""), args); + Log.MessageNetworked(string.Format(Lang.GIVEOBJECT, iCount, name, target.name, ""), args); } else { diff --git a/Code/DT-Commands/CurrentRun.cs b/Code/DT-Commands/CurrentRun.cs index 5be2033..8f58db6 100644 --- a/Code/DT-Commands/CurrentRun.cs +++ b/Code/DT-Commands/CurrentRun.cs @@ -191,8 +191,7 @@ private static void PreventInteractableSpawns(SceneDirector obj) { if (noInteractables) { - obj.interactableCredit = 0; - //obj.teleporterSpawnCard = null; + obj.onPopulateCreditMultiplier = 0; } } @@ -230,13 +229,7 @@ private static void CCKillAll(ConCommandArgs args) Log.MessageNetworked(Lang.NOTINARUN_ERROR, args, LogLevel.MessageClientOnly); return; } - bool trueKill = false; - if (args.Count > 1 && args[1] != Lang.DEFAULT_VALUE && !Util.TryParseBool(args[1], out trueKill)) - { - Log.MessageNetworked(String.Format(Lang.PARSE_ERROR, "trueKill", "int or bool"), args, LogLevel.MessageClientOnly); - return; - } - + if (args.Count > 0 && args[0] != Lang.DEFAULT_VALUE) { TeamIndex team = TeamIndex.Monster; @@ -249,40 +242,11 @@ private static void CCKillAll(ConCommandArgs args) int count = 0; foreach (var teamComponent in TeamComponent.GetTeamMembers(team).ToList()) - { - if (trueKill && teamComponent.body.master) - { - teamComponent.body.master.TrueKill(); - count++; - } - else - { - var healthComponent = teamComponent.GetComponent(); - if (healthComponent) - { - - healthComponent.Suicide(null); - if (!healthComponent.alive) - { - count++; - } - } - } - - - } - string a = (trueKill ? "True " : "" ); - Log.MessageNetworked($"{a}Killed {count} of team {team}.", args); - } - else - { - int count = 0; - int countV = 0; - foreach (var teamComponent in TeamComponent.GetTeamMembers(TeamIndex.Monster).ToList()) { var healthComponent = teamComponent.GetComponent(); if (healthComponent) { + healthComponent.Suicide(null); if (!healthComponent.alive) { @@ -290,24 +254,13 @@ private static void CCKillAll(ConCommandArgs args) } } } - foreach (var teamComponent in TeamComponent.GetTeamMembers(TeamIndex.Void).ToList()) - { - var healthComponent = teamComponent.GetComponent(); - if (healthComponent) - { - healthComponent.Suicide(null); - if (!healthComponent.alive) - { - countV++; - } - } - } - Log.MessageNetworked($"Killed {count} of team {TeamIndex.Monster}.", args); - Log.MessageNetworked($"Killed {countV} of team {TeamIndex.Void}.", args); + Log.MessageNetworked($"Killed {count} of team {team}.", args); + } + else + { + DebugToolkit.InvokeCMD(args.sender, "kill_all", ((int)TeamIndex.Monster).ToString()); + DebugToolkit.InvokeCMD(args.sender, "kill_all", ((int)TeamIndex.Void).ToString()); } - - - } [ConCommand(commandName = "time_scale", flags = ConVarFlags.Engine | ConVarFlags.ExecuteOnServer, helpText = Lang.TIMESCALE_HELP)] @@ -329,6 +282,16 @@ private static void CCTimeScale(ConCommandArgs args) TimescaleNet.Invoke(scale); } + public static float prevTimeScale = 0; + [ConCommand(commandName = "toggle_time", flags = ConVarFlags.None, helpText = Lang.TOGGLETIME_HELP)] + private static void CCTogglePause(ConCommandArgs args) + { + float newTimeScale = prevTimeScale; + prevTimeScale = Time.timeScale; + Time.timeScale = newTimeScale; + TimescaleNet.Invoke(newTimeScale); + } + [ConCommand(commandName = "stop_timer", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.STOPTIMER_HELP)] [AutoComplete(Lang.ENABLE_ARGS)] private static void CCPauseTimer(ConCommandArgs args) @@ -771,11 +734,55 @@ private static void CCSetTime(ConCommandArgs args) } - [ConCommand(commandName = "evolve_lemurian", flags = ConVarFlags.ExecuteOnServer, helpText = "Evolves all Devoted Lemurians")] - [ConCommand(commandName = "evolve_lemurians", flags = ConVarFlags.ExecuteOnServer, helpText = "Evolves all Devoted Lemurians")] - public static void CC_evolve_lemurian(ConCommandArgs args) + [ConCommand(commandName = "evolve_lemurians", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.EVOLVE_LEMURIAN_HELP)] + [AutoComplete(Lang.PLAYER_OR_ALL_OPTIONAL_ARGS)] + public static void CCEvolveLemurians(ConCommandArgs args) { - DevotionInventoryController.ActivateAllDevotedEvolution(); + if (!Run.instance) + { + Log.MessageNetworked(Lang.NOTINARUN_ERROR, args, LogLevel.MessageClientOnly); + return; + } + bool all = false; + bool succeeded = false; + + NetworkUser player = args.sender; + if (args.Count > 0) + { + player = Util.GetNetUserFromString(args.userArgs, 0); + if (player == null) + { + Log.MessageNetworked(Lang.PLAYER_NOTFOUND, args, LogLevel.MessageClientOnly); + return; + } + } + if (args.Count > 0 && args[0].ToUpperInvariant() == Lang.ALL) + { + all = true; + } + else if (!all && player == null) + { + Log.MessageNetworked(Lang.PLAYER_NOTFOUND, args, LogLevel.MessageClientOnly); + return; + } + + foreach (DevotionInventoryController devotionInventoryController in DevotionInventoryController.InstanceList) + { + if (all || devotionInventoryController.SummonerMaster == player.master) + { + succeeded = true; + devotionInventoryController.UpdateAllMinions(true); + } + } + if (all) + { + Log.MessageNetworked(succeeded ? "Evolved all devoted Lemurians." : "There are no devoted lemurians", args); + } + else + { + Log.MessageNetworked(succeeded ? $"Evolved {player.userName}'s devoted Lemurians." : $"{player.userName} does not own any devoted lemurians", args); + } + } } @@ -800,7 +807,7 @@ internal static void Invoke(float scale) private void RpcApplyTimescale(float scale) { Time.timeScale = scale; - Message("Timescale set to: " + scale + " "); + Message("Timescale set to: " + scale); } } } diff --git a/Code/DT-Commands/Drones.cs b/Code/DT-Commands/Drones.cs index b063556..7d7eb69 100644 --- a/Code/DT-Commands/Drones.cs +++ b/Code/DT-Commands/Drones.cs @@ -1,14 +1,7 @@ using RoR2; -using RoR2.Artifacts; using System; -using System.Collections.Generic; using System.Text; -using System.Xml.Linq; -using UnityEngine; -using UnityEngine.AddressableAssets; -using UnityEngine.Networking; using static DebugToolkit.Log; -using static DebugToolkit.Util; namespace DebugToolkit.Commands { @@ -36,7 +29,6 @@ private static void CCListDrone(ConCommandArgs args) [AutoComplete(Lang.GIVEDRONE_ARGS)] private static void CCGiveDrone(ConCommandArgs args) { - //give_drone {name} {amount} {tier} if (!Run.instance) { Log.MessageNetworked(Lang.NOTINARUN_ERROR, args, LogLevel.MessageClientOnly); @@ -49,40 +41,39 @@ private static void CCGiveDrone(ConCommandArgs args) return; } - int amount = 1; - if (args.Count > 1 && args[1] != Lang.DEFAULT_VALUE && !TextSerialization.TryParseInvariant(args[1], out amount)) + int dCount = 1; + if (args.Count > 1 && args[1] != Lang.DEFAULT_VALUE && !TextSerialization.TryParseInvariant(args[1], out dCount)) { Log.MessageNetworked(String.Format(Lang.PARSE_ERROR, "count", "int"), args, LogLevel.MessageClientOnly); return; } - int tier = 1; - if (args.Count > 2 && args[2] != Lang.DEFAULT_VALUE && !TextSerialization.TryParseInvariant(args[2], out tier)) + if (dCount < 0) { - Log.MessageNetworked(String.Format(Lang.PARSE_ERROR, "tier", "int"), args, LogLevel.MessageClientOnly); + Log.MessageNetworked(string.Format(Lang.NEGATIVE_ARG, "count"), args, LogLevel.MessageClientOnly); return; } - - var target = Buffs.ParseTarget(args, 3); - if (target.failMessage != null) + int tier = 1; + if (args.Count > 2 && args[2] != Lang.DEFAULT_VALUE && !TextSerialization.TryParseInvariant(args[2], out tier)) { - Log.MessageNetworked(target.failMessage, args, LogLevel.MessageClientOnly); + Log.MessageNetworked(String.Format(Lang.PARSE_ERROR, "drone_tier", "int"), args, LogLevel.MessageClientOnly); return; } - if (!target.body) + if (tier < 0) { - Log.MessageNetworked("No target body found", args, LogLevel.MessageClientOnly); + Log.MessageNetworked(string.Format(Lang.NEGATIVE_ARG, "drone_tier"), args, LogLevel.MessageClientOnly); return; } - - var drone = StringFinder.Instance.GetDroneFromPartial(args[0]); - if (drone == DroneIndex.None) + + var target = Buffs.ParseTarget(args, 3); + if (target.failMessage != null) { - Log.MessageNetworked(string.Format(Lang.OBJECT_NOTFOUND, "drone", args[0]), args, LogLevel.MessageClientOnly); + Log.MessageNetworked(target.failMessage, args, LogLevel.MessageClientOnly); return; } + + var drone = StringFinder.Instance.GetDroneFromPartial(args[0]); DroneDef droneDef = DroneCatalog.GetDroneDef(drone); - - if (droneDef == null) + if (drone == DroneIndex.None || !droneDef) { Log.MessageNetworked(string.Format(Lang.OBJECT_NOTFOUND, "drone", args[0]), args, LogLevel.MessageClientOnly); return; @@ -92,14 +83,9 @@ private static void CCGiveDrone(ConCommandArgs args) Log.MessageNetworked(string.Format(Lang.EXPANSION_LOCKED, "drone", Util.GetExpansion(droneDef.requiredExpansion)), args, LogLevel.MessageClientOnly); return; } - if (amount > 50) - { - amount = 50; - Log.MessageNetworked($"Limited to 50, please don't spawn too many things at once.", args, LogLevel.MessageClientOnly); - } - if (amount > 0) + if (dCount > 0) { - for (int i = 0; i < amount; i++) + for (int i = 0; i < dCount; i++) { CharacterMaster newlySpawnedDrone = new MasterSummon { @@ -117,7 +103,7 @@ private static void CCGiveDrone(ConCommandArgs args) } } var name = droneDef.name; - Log.MessageNetworked(string.Format(Lang.GIVEDRONE, amount, name, target.name, tier), args); + Log.MessageNetworked(string.Format(Lang.GIVEDRONE, dCount, name, target.name, tier), args); } else { @@ -125,9 +111,10 @@ private static void CCGiveDrone(ConCommandArgs args) } } - + + [ConCommand(commandName = "remove_all_drones", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.REMOVEALLDRONES_HELP)] - [AutoComplete(Lang.KICK_ARGS)] + [AutoComplete(Lang.REMOVEALLDRONES_ARGS)] private static void CCRemoveDrones(ConCommandArgs args) { if (!Run.instance) @@ -138,7 +125,7 @@ private static void CCRemoveDrones(ConCommandArgs args) bool isDedicatedServer = args.sender == null; if (isDedicatedServer && (args.Count < 1 || args[0] == Lang.DEFAULT_VALUE)) { - Log.MessageNetworked(Lang.INSUFFICIENT_ARGS + Lang.KICK_ARGS, args, LogLevel.MessageClientOnly); + Log.MessageNetworked(Lang.INSUFFICIENT_ARGS + Lang.REMOVEALLDRONES_ARGS, args, LogLevel.MessageClientOnly); return; } @@ -170,8 +157,8 @@ private static void CCRemoveDrones(ConCommandArgs args) Log.MessageNetworked(string.Format(Lang.REMOVEDRONES, removedAmount, target.name), args); } - [ConCommand(commandName = "kill_minions", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.KILL_ALL_MINIONS_HELP)] - [AutoComplete(Lang.KICK_ARGS)] + [ConCommand(commandName = "kill_all_minions", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.KILL_ALL_MINIONS_HELP)] + [AutoComplete(Lang.REMOVEALLDRONES_ARGS)] private static void CCKillMinions(ConCommandArgs args) { if (!Run.instance) @@ -182,7 +169,7 @@ private static void CCKillMinions(ConCommandArgs args) bool isDedicatedServer = args.sender == null; if (isDedicatedServer && (args.Count < 1 || args[0] == Lang.DEFAULT_VALUE)) { - Log.MessageNetworked(Lang.INSUFFICIENT_ARGS + Lang.KICK_ARGS, args, LogLevel.MessageClientOnly); + Log.MessageNetworked(Lang.INSUFFICIENT_ARGS + Lang.PLAYER_ARGS, args, LogLevel.MessageClientOnly); return; } @@ -192,8 +179,7 @@ private static void CCKillMinions(ConCommandArgs args) Log.MessageNetworked(target.failMessage, args, LogLevel.MessageClientOnly); return; } - - + var owner = target.inventory.GetComponent(); if (owner == null || owner.group == null || owner.group.memberCount == 0) { diff --git a/Code/DT-Commands/Items.cs b/Code/DT-Commands/Items.cs index ece8d2b..1f23f92 100644 --- a/Code/DT-Commands/Items.cs +++ b/Code/DT-Commands/Items.cs @@ -67,25 +67,7 @@ private static void CCListEquip(ConCommandArgs args) var s = sb.Length > 0 ? sb.ToString().TrimEnd('\n') : string.Format(Lang.NOMATCH_ERROR, "equipment", arg); Log.MessageNetworked(s, args, LogLevel.MessageClientOnly); } - - [ConCommand(commandName = "list_drone", flags = ConVarFlags.None, helpText = Lang.LISTDRONE_HELP)] - [AutoComplete(Lang.LISTQUERY_ARGS)] - private static void CCListDrone(ConCommandArgs args) - { - var sb = new StringBuilder(); - var arg = args.Count > 0 ? args[0] : ""; - var indices = StringFinder.Instance.GetDronesFromPartial(arg); - foreach (var index in indices) - { - var definition = DroneCatalog.GetDroneDef(index); - var realName = Language.currentLanguage.GetLocalizedStringByToken(definition.nameToken); - bool enabled = Run.instance && Run.instance.IsDroneAvailable(index); - sb.AppendLine($"[{(int)index}]{definition.name} \"{realName}\" (enabled={enabled})"); - } - var s = sb.Length > 0 ? sb.ToString().TrimEnd('\n') : string.Format(Lang.NOMATCH_ERROR, "drone", arg); - Log.MessageNetworked(s, args, LogLevel.MessageClientOnly); - } - + [ConCommand(commandName = "list_pickups", flags = ConVarFlags.None, helpText = Lang.LISTDRONE_HELP)] [AutoComplete(Lang.LISTQUERY_ARGS)] private static void CCListPickup(ConCommandArgs args) @@ -209,7 +191,7 @@ private static void CCGiveItem(ConCommandArgs args) return; } GiveItem(inventory, item, amount, type); - Log.MessageNetworked(string.Format(Lang.GIVEITEM, amount, name, target.name), args); + Log.MessageNetworked(string.Format(Lang.GIVEOBJECT, amount, name, target.name), args); } else if (amount < 0) { @@ -235,110 +217,10 @@ public static string getItemTypeName(ItemType type) return ""; case ItemType.Temp: return "Temporary "; //Saturated by 50% Temp color - //return "temporary"; //Bit hard to see in the console } return type.ToString(); } - [ConCommand(commandName = "give_drone", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.GIVEDRONE_HELP)] - [AutoComplete(Lang.GIVEDRONE_ARGS)] - private static void CCGiveDrone(ConCommandArgs args) - { - //give_drone {name} {amount} {tier} - if (!Run.instance) - { - Log.MessageNetworked(Lang.NOTINARUN_ERROR, args, LogLevel.MessageClientOnly); - return; - } - bool isDedicatedServer = args.sender == null; - if (args.Count == 0 || (isDedicatedServer && (args.Count < 4 || args[3] == Lang.DEFAULT_VALUE))) - { - Log.MessageNetworked(Lang.INSUFFICIENT_ARGS + Lang.GIVEITEM_ARGS, args, LogLevel.MessageClientOnly); - return; - } - - int amount = 1; - if (args.Count > 1 && args[1] != Lang.DEFAULT_VALUE && !TextSerialization.TryParseInvariant(args[1], out amount)) - { - Log.MessageNetworked(String.Format(Lang.PARSE_ERROR, "count", "int"), args, LogLevel.MessageClientOnly); - return; - } - int tier = 1; - if (args.Count > 2 && args[2] != Lang.DEFAULT_VALUE && !TextSerialization.TryParseInvariant(args[2], out tier)) - { - Log.MessageNetworked(String.Format(Lang.PARSE_ERROR, "tier", "int"), args, LogLevel.MessageClientOnly); - return; - } - if (tier < 0) - { - Log.MessageNetworked(string.Format(Lang.NEGATIVE_ARG, "count"), args, LogLevel.MessageClientOnly); - return; - } - var target = Buffs.ParseTarget(args, 3); - if (target.failMessage != null) - { - Log.MessageNetworked(target.failMessage, args, LogLevel.MessageClientOnly); - return; - } - if (!target.body) - { - Log.MessageNetworked("No target body found", args, LogLevel.MessageClientOnly); - return; - } - - var drone = StringFinder.Instance.GetDroneFromPartial(args[0]); - if (drone == DroneIndex.None) - { - Log.MessageNetworked(string.Format(Lang.OBJECT_NOTFOUND, "drone", args[0]), args, LogLevel.MessageClientOnly); - return; - } - DroneDef droneDef = DroneCatalog.GetDroneDef(drone); - - if (droneDef == null) - { - Log.MessageNetworked(string.Format(Lang.OBJECT_NOTFOUND, "drone", args[0]), args, LogLevel.MessageClientOnly); - return; - } - if (Run.instance.IsDroneExpansionLocked(drone)) - { - Log.MessageNetworked(string.Format(Lang.EXPANSION_LOCKED, "drone", Util.GetExpansion(droneDef.requiredExpansion)), args, LogLevel.MessageClientOnly); - return; - } - if (amount > 50) - { - amount = 50; - Log.MessageNetworked($"Limited to 50, please don't spawn too many things at once.", args, LogLevel.MessageClientOnly); - } - if (amount > 0) - { - for (int i = 0; i < amount; i++) - { - CharacterMaster newlySpawnedDrone = new MasterSummon - { - masterPrefab = droneDef.masterPrefab, - position = target.body.transform.position, - rotation = target.body.transform.rotation, - summonerBodyObject = target.body.gameObject, - ignoreTeamMemberLimit = true, - useAmbientLevel = true, - enablePrintController = true - }.Perform(); - if (tier > 1) - { - newlySpawnedDrone.inventory.GiveItemPermanent(DLC3Content.Items.DroneUpgradeHidden, (tier - 1)); - } - } - var name = droneDef.name; - Log.MessageNetworked(string.Format(Lang.GIVEDRONE, amount, name, target.name, tier), args); - } - else - { - Log.MessageNetworked("Nothing happened", args); - } - - } - - [ConCommand(commandName = "random_items", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.RANDOMITEM_HELP)] [AutoComplete(Lang.RANDOMITEM_ARGS)] private static void CCRandomItemsTiered(ConCommandArgs args) @@ -440,7 +322,7 @@ private static void CCGiveEquipment(ConCommandArgs args) else if (args[0] == "-1") { inventory.SetEquipmentIndex(EquipmentIndex.None, true); - Log.MessageNetworked($"Removed current Equipment from {target.name}", args); + Log.MessageNetworked(string.Format(Lang.REMOVEDEQUIP, target.name), args); return; } else @@ -503,11 +385,11 @@ private static void CCCreatePickup(ConCommandArgs args) return; } - ItemType type = ItemType.Permanent; + PickupType type = PickupType.Permanent; if (args.Count > 2 && args[2] != Lang.DEFAULT_VALUE) { - type = ParseItemType(args, 2); - if (type <= ItemType.None || type >= ItemType.Count) + type = ParsePickupType(args, 2); + if (type <= PickupType.None || type >= PickupType.Count) { Log.MessageNetworked(String.Format(Lang.INVALID_ARG_VALUE, "type"), args, LogLevel.MessageClientOnly); return; @@ -606,7 +488,7 @@ private static void CCCreatePickup(ConCommandArgs args) { foundResults += $"{drone}|{def3.name}|{Language.GetString(def3.nameToken)}"; } - Log.MessageNetworked(string.Format(Lang.CREATEPICKUP_AMBIGIOUS_4, foundResults), args, LogLevel.MessageClientOnly); + Log.MessageNetworked(string.Format(Lang.CREATEPICKUP_AMBIGIOUS, foundResults), args, LogLevel.MessageClientOnly); return; } else if (equipment != EquipmentIndex.None) @@ -635,7 +517,7 @@ private static void CCCreatePickup(ConCommandArgs args) pickup = new UniquePickup { pickupIndex = final, - decayValue = type == ItemType.Temp ? 1f : 0f, + decayValue = type == PickupType.Temp ? 1f : 0f, //upgradeValue }, }, body.transform.position, body.inputBank.aimDirection * 30f); @@ -824,7 +706,7 @@ private static void CCRemoveEquipment(ConCommandArgs args) } target.inventory.SetEquipmentIndex(EquipmentIndex.None, true); - Log.MessageNetworked($"Removed current Equipment from {target.name}", args); + Log.MessageNetworked(string.Format(Lang.REMOVEDEQUIP, target.name), args); } [ConCommand(commandName = "restock_equip", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.RESTOCKEQUIP_HELP)] @@ -871,13 +753,28 @@ private static void CCRestockEquip(ConCommandArgs args) internal enum ItemType { - None, + None = -1, Permanent, Temp, Channeled, Count, } - + internal enum PickupType + { + None = -1, + Permanent, + Temp, + Count, + } + internal enum PickupCategory + { + Any, + Item, + Equip, + Drone, + Pickup, + Count, + } private static int GetItemCount(Inventory inventory, ItemIndex itemIndex, ItemType type) { switch (type) @@ -940,6 +837,14 @@ private static ItemType ParseItemType(ConCommandArgs args, int index) } return ItemType.Permanent; } + private static PickupType ParsePickupType(ConCommandArgs args, int index) + { + if (args.Count > index && args[index] != Lang.DEFAULT_VALUE) + { + return Enum.TryParse(args[index], true, out PickupType itemType) ? itemType : PickupType.None; + } + return PickupType.Permanent; + } public static CommandTarget ParseTarget(ConCommandArgs args, int index) { @@ -1062,10 +967,10 @@ private static BasicPickupDropTable ParseDroptable(ConCommandArgs args, int inde droptable.canDropBeReplaced = canDropBeReplaced; if (args.Count < index + 1 || args[index] == Lang.DEFAULT_VALUE) { - droptable.Add(availableDropLists[ItemTier.Tier1], 1f); - droptable.Add(availableDropLists[ItemTier.Tier2], 1f); - droptable.Add(availableDropLists[ItemTier.Tier3], 1f); - droptable.Add(availableDropLists[ItemTier.Boss], 1f); + droptable.Add(availableDropLists[ItemTier.Tier1], 100f); + droptable.Add(availableDropLists[ItemTier.Tier2], 60f); + droptable.Add(availableDropLists[ItemTier.Tier3], 4f); + droptable.Add(availableDropLists[ItemTier.Boss], 4f); } else if (args[index].ToUpperInvariant() == Lang.ALL) { @@ -1190,7 +1095,5 @@ private static DevotionInventoryController GetDevotionController(CharacterMaster } return controller; } - - } } diff --git a/Code/DT-Commands/LobbyManagement.cs b/Code/DT-Commands/LobbyManagement.cs index edc4894..43246f2 100644 --- a/Code/DT-Commands/LobbyManagement.cs +++ b/Code/DT-Commands/LobbyManagement.cs @@ -1,6 +1,7 @@ using DebugToolkit.Permissions; using RoR2; using RoR2.Networking; +using System; using UnityEngine; using UnityEngine.Networking; using static DebugToolkit.Log; @@ -10,13 +11,13 @@ namespace DebugToolkit.Commands class LobbyManagement { [ConCommand(commandName = "kick", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.KICK_HELP)] - [AutoComplete(Lang.KICK_ARGS)] + [AutoComplete(Lang.PLAYER_ARGS)] [RequiredLevel] private static void CCKick(ConCommandArgs args) { if (args.Count == 0) { - Log.MessageNetworked(Lang.INSUFFICIENT_ARGS + Lang.KICK_ARGS, args, LogLevel.Error); + Log.MessageNetworked(Lang.INSUFFICIENT_ARGS + Lang.PLAYER_ARGS, args, LogLevel.Error); return; } var client = GetClientFromArgs(args); @@ -47,42 +48,51 @@ private static void CCBan(ConCommandArgs args) } [ConCommand(commandName = "true_kill", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.TRUEKILL_HELP)] - [AutoComplete(Lang.TRUEKILL_ARGS)] + [AutoComplete(Lang.PLAYERPINGED_OR_ALL)] private static void CCTrueKill(ConCommandArgs args) { if (args.sender == null && (args.Count < 1 || args[0] == Lang.DEFAULT_VALUE)) { - Log.Message(Lang.INSUFFICIENT_ARGS + Lang.TRUEKILL_ARGS, LogLevel.Error); + Log.Message(Lang.INSUFFICIENT_ARGS + Lang.PLAYER_OR_PINGED, LogLevel.Error); return; } - CharacterMaster master = args.sender?.master; + + CharacterMaster master = args.sender.master; if (args.Count > 0) { - NetworkUser player = Util.GetNetUserFromString(args.userArgs); - if (player == null) + if (args[0].ToUpperInvariant() == Lang.ALL) { - Log.MessageNetworked(Lang.PLAYER_NOTFOUND, args, LogLevel.MessageClientOnly); + foreach (var player in PlayerCharacterMasterController.instances) + { + player.master.godMode = false; + player.master.UpdateBodyGodMode(); + player.master.TrueKill(); + } + Log.MessageNetworked("All players were killed by server.", args); return; } - master = player.master; + else + { + var target = Buffs.ParseTarget(args, 0); + if (target.failMessage != null) + { + Log.MessageNetworked(target.failMessage, args, LogLevel.MessageClientOnly); + return; + } + master = target.body.master; + } + } + if (!master) + { + Log.MessageNetworked(Lang.BODY_NOTFOUND, args, LogLevel.MessageClientOnly); + return; } master.godMode = false; master.UpdateBodyGodMode(); master.TrueKill(); Log.MessageNetworked(master.name + " was killed by server.", args); } - [ConCommand(commandName = "true_kill_all", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.TRUEKILL_HELP)] - private static void CCTrueKillAll(ConCommandArgs args) - { - foreach (var player in PlayerCharacterMasterController.instances) - { - player.master.godMode = false; - player.master.UpdateBodyGodMode(); - player.master.TrueKill(); - - } - Log.MessageNetworked("Everyone was killed by server.", args); - } + private static NetworkConnection GetClientFromArgs(ConCommandArgs args) { diff --git a/Code/DT-Commands/Macros.cs b/Code/DT-Commands/Macros.cs index 9e87289..3dc3dd0 100644 --- a/Code/DT-Commands/Macros.cs +++ b/Code/DT-Commands/Macros.cs @@ -1,5 +1,4 @@ using RoR2; -using UnityEngine.Networking; namespace DebugToolkit.Commands { @@ -36,16 +35,14 @@ private static void LateGame(ConCommandArgs args) } Invoke(a, "set_scene", "bazaar"); } - - //Is there any conflict in having it be the same convar as vanilla indev builds? - [ConCommand(commandName = "peace", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.MACRO_DTPEACE_HELP)] + [ConCommand(commandName = "dtpeace", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.MACRO_DTPEACE_HELP)] private static void Peace(ConCommandArgs args) { Invoke(args.sender, "kill_all", "2", "1"); Invoke(args.sender, "kill_all", "4", "1"); Invoke(args.sender, "no_enemies", "1"); - //Vanilla peace also sets god 1 but ehh idk i dont need that + Invoke(args.sender, "god", "1"); } [ConCommand(commandName = "dtzoom", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.MACRO_DTZOOM_HELP)] @@ -61,22 +58,11 @@ private static void Damage(ConCommandArgs args) Invoke(args.sender, "give_item", "boostdamage", "9999990"); } - [ConCommand(commandName = "scanner", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.MACRO_SCANNER_HELP)] [ConCommand(commandName = "dtscanner", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.MACRO_SCANNER_HELP)] public static void CCScanner(ConCommandArgs args) { - if (!args.senderMaster) - { - return; - } - if (!NetworkServer.active) - { - return; - } Invoke(args.sender, "give_item", "BoostEquipmentRecharge", "100"); Invoke(args.sender, "give_equip", "Scanner"); - //args.senderMaster.inventory.SetEquipmentIndex(RoR2Content.Equipment.Scanner.equipmentIndex, false); - //args.senderMaster.inventory.GiveItemPermanent(RoR2Content.Items.BoostEquipmentRecharge, 100); } diff --git a/Code/DT-Commands/Miscellaneous.cs b/Code/DT-Commands/Miscellaneous.cs index 2b12726..89e2f6e 100644 --- a/Code/DT-Commands/Miscellaneous.cs +++ b/Code/DT-Commands/Miscellaneous.cs @@ -1,6 +1,8 @@ using BepInEx.Bootstrap; using RoR2; using System.Collections; +using System.Linq; +using System.Text; using UnityEngine; using UnityEngine.UIElements; @@ -80,52 +82,35 @@ static IEnumerator InvokeRoutine(System.Action action, float delay) action(); } } - - public static float prevTimeScale = 0; - [ConCommand(commandName = "toggle_time", flags = ConVarFlags.None, helpText = Lang.TOGGLETIME_HELP)] - private static void CC_TogglePause(ConCommandArgs args) - { - float newTimeScale = prevTimeScale; - prevTimeScale = Time.timeScale; - Time.timeScale = newTimeScale; - TimescaleNet.Invoke(newTimeScale); - } - - [ConCommand(commandName = "list_mods", flags = ConVarFlags.None, helpText = "Lists installed mod names to get them for compatibility, then lists all mods tagged as required by all")] - [AutoComplete(Lang.LISTMODS_ARGS)] + + [ConCommand(commandName = "dump_mods", flags = ConVarFlags.None, helpText = Lang.DUMPMODS_HELP)] public static void CCMods(ConCommandArgs args) { int requiredByAll = args.TryGetArgInt(0).GetValueOrDefault(0); - UnityEngine.Debug.Log(requiredByAll); - string log = string.Empty; - if (requiredByAll == 0 || requiredByAll == 1) + + StringBuilder log = new StringBuilder(); + + log.Append("All loaded mods\n\n"); + foreach (var a in BepInEx.Bootstrap.Chainloader.PluginInfos) { - log += "All loaded mods\n\n"; - foreach (var a in BepInEx.Bootstrap.Chainloader.PluginInfos) - { - log += a.ToString() + "\n"; - } + log.Append(a.ToString()); + log.Append("\n"); } - if (requiredByAll == 0) + log.Append("\n"); + if (NetworkModCompatibilityHelper._networkModList.Length == 0) { - log += "\n"; + log.Append("No mods tagged as RequiredByAll. This mod pack is Vanilla compatible."); } - if (requiredByAll == 0 || requiredByAll == 2) + else { - if (NetworkModCompatibilityHelper._networkModList.Length == 0) - { - log += "No mods tagged as RequiredByAll. This mod pack is Vanilla compatible."; - } - else + log.Append("Mods tagged as RequiredByAll\n\n"); + foreach (var a in NetworkModCompatibilityHelper.networkModList) { - log += "Mods tagged as RequiredByAll\n\n"; - foreach (var a in NetworkModCompatibilityHelper._networkModList) - { - log += a.ToString() + "\n"; - } + log.Append(a.ToString()); + log.Append("\n"); } } - Debug.Log(log); + Log.Message(log.ToString()); } } diff --git a/Code/DT-Commands/Money.cs b/Code/DT-Commands/Money.cs index 3b73c28..6ecc0e9 100644 --- a/Code/DT-Commands/Money.cs +++ b/Code/DT-Commands/Money.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Runtime.CompilerServices; +using System.Xml.Linq; using UnityEngine; using static DebugToolkit.Log; @@ -10,7 +11,7 @@ namespace DebugToolkit.Commands class Money { [ConCommand(commandName = "give_lunar", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.GIVELUNAR_HELP)] - [ConCommand(commandName = "give_lunarcoin", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.GIVELUNAR_HELP)] + [ConCommand(commandName = "give_void", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.GIVEVOID_HELP)] [AutoComplete(Lang.GIVELUNAR_ARGS)] private static void CCGiveLunar(ConCommandArgs args) { @@ -21,7 +22,7 @@ private static void CCGiveLunar(ConCommandArgs args) } if (args.sender == null) { - Log.Message("Can't modify Lunar coins of other users directly.", LogLevel.MessageClientOnly); + Log.Message("Can't modify Lunar Coins/Void Markers of other users directly.", LogLevel.MessageClientOnly); return; } int amount = 1; @@ -32,62 +33,42 @@ private static void CCGiveLunar(ConCommandArgs args) } string str = "Nothing happened. Big surprise."; NetworkUser target = args.sender; - if (amount > 0) - { - target.AwardLunarCoins((uint)amount); - str = string.Format(Lang.GIVELUNAR_2, "Gave", amount); - } - if (amount < 0) - { - amount *= -1; - target.DeductLunarCoins((uint)(amount)); - str = string.Format(Lang.GIVELUNAR_2, "Removed", amount); - } - Log.MessageNetworked(str, args); - } - [ConCommand(commandName = "give_void", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.GIVEVOID_HELP)] - [ConCommand(commandName = "give_voidcoin", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.GIVEVOID_HELP)] - [AutoComplete(Lang.GIVELUNAR_ARGS)] - private static void CCGiveVoidCoin(ConCommandArgs args) - { - if (!Run.instance) - { - Log.MessageNetworked(Lang.NOTINARUN_ERROR, args, LogLevel.MessageClientOnly); - return; - } - if (args.sender == null) - { - Log.Message("Can't modify Lunar coins of other users directly.", LogLevel.MessageClientOnly); - return; - } - int amount = 1; - if (args.Count > 0 && args[0] != Lang.DEFAULT_VALUE && !TextSerialization.TryParseInvariant(args[0], out amount)) - { - Log.MessageNetworked(String.Format(Lang.PARSE_ERROR, "amount", "int"), args, LogLevel.MessageClientOnly); - return; - } - string str = "Nothing happened. Big surprise."; - CharacterMaster master = args.senderMaster; - if (!master) - { - Log.MessageNetworked("No master to send coins to",args, LogLevel.MessageClientOnly); - return; - } - if (amount > 0) - { - master.GiveVoidCoins((uint)amount); - str = string.Format(Lang.GIVEVOIDC_2, "Gave", amount); - } - if (amount < 0) + + if (amount != 0) { - master.GiveVoidCoins((uint)(amount)); - str = string.Format(Lang.GIVEVOIDC_2, "Removed", amount); + bool voidMarker = args.commandName == "give_void"; + if (voidMarker) + { + if (amount < 0) + { + amount = -amount; + target.master.voidCoins = HGMath.UintSafeSubtract(target.master.voidCoins, (uint)amount); + } + else + { + target.master.GiveVoidCoins((uint)amount); + } + str = string.Format(Lang.GIVEVOIDC_2, amount > 0 ? "Gave" : "Removed", amount); + } + else + { + if (amount < 0) + { + amount = -amount; + target.DeductLunarCoins((uint)(amount)); + } + else + { + target.AwardLunarCoins((uint)amount); + } + str = string.Format(Lang.GIVELUNAR_2, amount > 0 ? "Gave" : "Removed", amount); + } } Log.MessageNetworked(str, args); } - + [ConCommand(commandName = "give_money", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.GIVEMONEY_HELP)] [AutoComplete(Lang.GIVEMONEY_ARGS)] private static void CCGiveMoney(ConCommandArgs args) @@ -142,24 +123,24 @@ private static void CCGiveMoney(ConCommandArgs args) [ConCommand(commandName = "rich", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.ALLMONEY_HELP)] [ConCommand(commandName = "poor", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.NO_MONEY_HELP)] - [AutoComplete(Lang.MONEY_ARGS)] - public static void CC_poor(ConCommandArgs args) + [AutoComplete(Lang.PLAYER_OR_ALL_OPTIONAL_ARGS)] + public static void CCSetMoney(ConCommandArgs args) { bool rich = args.commandName == "rich"; if (args.Count > 0 && args[0].ToUpperInvariant() != Lang.ALL && args[0].ToUpperInvariant() != Lang.DEFAULT_VALUE) { - NetworkUser player = Util.GetNetUserFromString(args.userArgs, 1); + NetworkUser player = Util.GetNetUserFromString(args.userArgs, 0); if (player != null) { if (rich) { player.master.GiveMoney(2000000000 - player.master.money); - Log.MessageNetworked("$$$", args); + Log.MessageNetworked(string.Format("Made {0} rich.", player.userName), args); } else { player.master.money = 0; - Log.MessageNetworked("-$", args); + Log.MessageNetworked(string.Format("Set {0}'s money to 0.", player.userName), args); } } else @@ -183,11 +164,11 @@ public static void CC_poor(ConCommandArgs args) } if (rich) { - Log.MessageNetworked("We're rich", args); + Log.MessageNetworked("We're rich.", args); } else { - Log.MessageNetworked("We're poor", args); + Log.MessageNetworked("Reset all money back to 0.", args); } } } diff --git a/Code/DT-Commands/PlayerCommands.cs b/Code/DT-Commands/PlayerCommands.cs index 8d722d5..64b5727 100644 --- a/Code/DT-Commands/PlayerCommands.cs +++ b/Code/DT-Commands/PlayerCommands.cs @@ -1,13 +1,9 @@ -using HG; using RoR2; using RoR2.ContentManagement; using RoR2.ExpansionManagement; using System; using System.Collections.Generic; -using System.Security.Cryptography; using UnityEngine; -using UnityEngine.Networking; -using UnityEngine.SocialPlatforms; using static DebugToolkit.Log; namespace DebugToolkit.Commands @@ -81,11 +77,10 @@ private static void CCBuddhaModeToggle(ConCommandArgs args) Log.MessageNetworked(String.Format(modeOn ? Lang.SETTING_ENABLED : Lang.SETTING_DISABLED, "Buddha mode"), args); } - [ConCommand(commandName = "buddhaenemy", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.BUDDHA_HELP2)] - [ConCommand(commandName = "budaenemy", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.BUDDHA_HELP2)] - [ConCommand(commandName = "invulenemy", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.BUDDHA_HELP2)] + [ConCommand(commandName = "buddhaenemy", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.BUDDHAENEMY_HELP)] + [ConCommand(commandName = "budaenemy", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.BUDDHAENEMY_HELP)] [AutoComplete(Lang.ENABLE_ARGS)] - private static void CCBuddhaMONSTERModeToggle(ConCommandArgs args) + private static void CCBuddhaMonstersToggle(ConCommandArgs args) { bool modeOn; if (args.Count > 0) @@ -102,25 +97,53 @@ private static void CCBuddhaMONSTERModeToggle(ConCommandArgs args) Hooks.buddhaMonsters = !Hooks.buddhaMonsters; modeOn = Hooks.buddhaMonsters; } - foreach (var body in CharacterBody.instancesList) + foreach (TeamComponent teamComponent in TeamComponent.GetTeamMembers(TeamIndex.Monster)) { - if (body && !body.isPlayerControlled) + if (teamComponent.body) { if (modeOn) { - body.bodyFlags |= RoR2.CharacterBody.BodyFlags.Buddha; + teamComponent.body.bodyFlags |= RoR2.CharacterBody.BodyFlags.Buddha; } else { - body.bodyFlags &= ~RoR2.CharacterBody.BodyFlags.Buddha; + teamComponent.body.bodyFlags &= ~RoR2.CharacterBody.BodyFlags.Buddha; } } } - - - Log.MessageNetworked(String.Format(modeOn ? Lang.SETTING_ENABLED : Lang.SETTING_DISABLED, "Monster Buddha mode"), args); + Log.MessageNetworked(String.Format(modeOn ? Lang.SETTING_ENABLED : Lang.SETTING_DISABLED, "Buddha mode for monsters"), args); } + [ConCommand(commandName = "godenemy", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.GOD_HELP)] + [AutoComplete(Lang.ENABLE_ARGS)] + private static void CCGodMonstersToggle(ConCommandArgs args) + { + bool modeOn; + if (args.Count > 0) + { + if (!Util.TryParseBool(args[0], out modeOn)) + { + Log.MessageNetworked(string.Format(Lang.PARSE_ERROR, "enable", "bool"), args, LogLevel.MessageClientOnly); + return; + } + Hooks.godMonsters = modeOn; + } + else + { + Hooks.godMonsters = !Hooks.godMonsters; + modeOn = Hooks.godMonsters; + } + foreach (TeamComponent teamComponent in TeamComponent.GetTeamMembers(TeamIndex.Monster)) + { + HealthComponent component = teamComponent.GetComponent(); + component.godMode = modeOn; + if (teamComponent.body.master) + { + teamComponent.body.master.godMode = modeOn; + } + } + Log.MessageNetworked(String.Format(modeOn ? Lang.SETTING_ENABLED : Lang.SETTING_DISABLED, "God mode for monsters"), args); + } [ConCommand(commandName = "noclip", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.NOCLIP_HELP)] @@ -174,11 +197,16 @@ private static void CCCursorTeleport(ConCommandArgs args) } - [ConCommand(commandName = "goto_boss", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.CURSORTELEPORT_HELP)] + [ConCommand(commandName = "goto_boss", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.GOTOBOSS_HELP)] private static void CCGoto_Boss(ConCommandArgs args) { + if (!Run.instance) + { + Log.MessageNetworked(Lang.NOTINARUN_ERROR, args, LogLevel.MessageClientOnly); + return; + } + string stage = Stage.instance.sceneDef.cachedName; - Component senderBody = args.GetSenderBody(); Vector3 newPosition = Vector3.zero; string destination = string.Empty; @@ -242,8 +270,15 @@ private static void CCGoto_Boss(ConCommandArgs args) Debug.Log("No Teleporter, Specific Location or Boss Monster found."); return; } - TeleportHelper.TeleportGameObject(senderBody.gameObject, newPosition); - Debug.Log($"Teleported you to {destination}"); + + foreach (PlayerCharacterMasterController player in PlayerCharacterMasterController.instances) + { + if (player.master.bodyInstanceObject) + { + TeleportHelper.TeleportGameObject(player.master.bodyInstanceObject, newPosition); + } + } + Debug.Log($"Teleported players to {destination}"); } @@ -289,18 +324,10 @@ private static void CCSpawnAs(ConCommandArgs args) Log.MessageNetworked(string.Format(Lang.EXPANSION_LOCKED, "body", Util.GetExpansion(expansion.requiredExpansion)), args, LogLevel.MessageClientOnly); return; } - - master.originalBodyPrefab = newBody; + master.bodyPrefab = newBody; - if (args.TryGetArgBool(1).GetValueOrDefault(true)) - { - master.originalBodyPrefab = newBody; - Log.MessageNetworked(args.sender.userName + " is spawning as " + newBody.name + " for the rest of the run.", args); - } - else - { - Log.MessageNetworked(args.sender.userName + " is spawning as " + newBody.name + " temporarily.", args); - } + master.originalBodyPrefab = newBody; + Log.MessageNetworked(args.sender.userName + " is spawning as " + newBody.name + " for the rest of the run.", args); if (!master.GetBody()) { @@ -375,7 +402,7 @@ private static void CCHurt(ConCommandArgs args) bool bypassCalc = false; if (args.Count > 2 && args[2] != Lang.DEFAULT_VALUE && !Util.TryParseBool(args[2], out bypassCalc)) { - Log.MessageNetworked(String.Format(Lang.PARSE_ERROR, "bypassCalc", "int or bool"), args, LogLevel.MessageClientOnly); + Log.MessageNetworked(String.Format(Lang.PARSE_ERROR, "direct", "bool"), args, LogLevel.MessageClientOnly); return; } var target = Buffs.ParseTarget(args, 1); @@ -764,59 +791,26 @@ internal static bool UpdateCurrentPlayerBody(out NetworkUser networkUser, out Ch return false; } - - - //loadout_set_skill_variant self <- adding cuz requested //Does not work - //[ConCommand(commandName = "loadout_set_skill_variant self", flags = ConVarFlags.ExecuteOnServer, helpText = "Switch Skills of current survivor Shorthand")] [ConCommand(commandName = "skill", flags = ConVarFlags.ExecuteOnServer, helpText = "[skill_slot] [skill_variant]\nSets the skill variant for the sender's user profile.")] - public static void CC_Skill(ConCommandArgs args) + public static void CCSetSkillShort(ConCommandArgs args) { - if (!args.sender) - { - Log.Message("Can't choose self if not in-game!", LogLevel.Error); - return; - } - if (args.Count < 2) - { - Log.MessageNetworked(Lang.INSUFFICIENT_ARGS + Lang.LOADOUTSKIN_ARGS, args, LogLevel.MessageClientOnly); - return; - } - BodyIndex argBodyIndex = BodyIndex.None; - if (args.senderBody) - { - argBodyIndex = args.senderBody.bodyIndex; - } - else - { - if (args.senderMaster && args.senderMaster.bodyPrefab) - { - argBodyIndex = args.senderMaster.bodyPrefab.GetComponent().bodyIndex; - } - else - { - argBodyIndex = args.sender.bodyIndexPreference; - } - } args.userArgs = new List { - argBodyIndex.ToString(), + "self", args[0], args[1], }; - UserProfile.CCLoadoutSetSkillVariant(args); - - - } + UserProfile.CCLoadoutSetSkillVariant(args); } [ConCommand(commandName = "skin", flags = ConVarFlags.ExecuteOnServer, helpText = "[skin_variant]\nSets the skin variant for the sender's user profile.")] - public static void CC_SKIN(ConCommandArgs args) + public static void CCSetSkinShort(ConCommandArgs args) { Macros.Invoke(args.sender, "loadout_set_skin_variant", "self", args.TryGetArgInt(0).GetValueOrDefault(-1).ToString()); } [ConCommand(commandName = "unlimited_junk", flags = ConVarFlags.ExecuteOnServer, helpText = "Toggle junk_unlimited. Makes skillchecks ingore junk cost.")] - public static void CC_JunkAlt(ConCommandArgs args) + public static void CCToggleUnlimitedJunk(ConCommandArgs args) { JunkController.junkUnlimited.value = !JunkController.junkUnlimited.value; if (JunkController.junkUnlimited.value) @@ -831,10 +825,9 @@ public static void CC_JunkAlt(ConCommandArgs args) - [ConCommand(commandName = "nocooldown", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.NOCOOLDOWN_HELP)] [ConCommand(commandName = "nocooldowns", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.NOCOOLDOWN_HELP)] - [AutoComplete(Lang.TARGET_PLAYER_PINGED)] - public static void CC_Cooldown(ConCommandArgs args) + [AutoComplete(Lang.PLAYER_OR_PINGED)] + public static void CCNoCooldowns(ConCommandArgs args) { var target = Buffs.ParseTarget(args, 0); if (target.failMessage != null) @@ -842,11 +835,6 @@ public static void CC_Cooldown(ConCommandArgs args) Log.MessageNetworked(target.failMessage, args, LogLevel.MessageClientOnly); return; } - if (!target.body) - { - Log.MessageNetworked("No target body found", args, LogLevel.MessageClientOnly); - return; - } bool NoCooldowns = false; GenericSkill[] slots = target.body.GetComponents(); foreach (GenericSkill slot in slots) @@ -866,22 +854,33 @@ public static void CC_Cooldown(ConCommandArgs args) } - //Idk what to do with this because like technically this does affect gameplay by turning off your hurtboxes and junk - [ConCommand(commandName = "invis", flags = ConVarFlags.None, helpText = "Turn off your model for screenshots")] - [ConCommand(commandName = "model", flags = ConVarFlags.None, helpText = "Turn off your model for screenshots")] - [ConCommand(commandName = "hide_model", flags = ConVarFlags.None, helpText = "Turn off your model for screenshots")] - public static void CC_TurnOffModel(ConCommandArgs args) + //This does affect gameplay because it deactivates all your hurtboxes too, not sure what to do about that. + [ConCommand(commandName = "hide_model", flags = ConVarFlags.None, helpText = Lang.TOGGLEMODE_HELP)] + public static void CCToggleModel(ConCommandArgs args) { - + if (args.sender == null) + { + Log.MessageWarning(Lang.DS_NOTAVAILABLE); + return; + } + if (!Run.instance) + { + Log.MessageNetworked(Lang.NOTINARUN_ERROR, args, LogLevel.MessageClientOnly); + return; + } + if (!args.senderBody) + { + Log.MessageNetworked("Can't hide your model while you're dead. " + Lang.USE_RESPAWN, args, LogLevel.MessageClientOnly); + return; + } GameObject mdl = args.senderBody.GetComponent().modelTransform.gameObject; mdl.SetActive(!mdl.activeSelf); Log.MessageNetworked(String.Format(!mdl.activeSelf ? Lang.SETTING_ENABLED : Lang.SETTING_DISABLED, "Invisible Model"), args); } - [ConCommand(commandName = "hud", flags = ConVarFlags.None, helpText = "Toggle hud_enable. Enable/disable the HUD.")] - [ConCommand(commandName = "ui", flags = ConVarFlags.None, helpText = "Toggle hud_enable. Enable/disable the HUD.")] - public static void CC_ToggleHUD(ConCommandArgs args) + [ConCommand(commandName = "toggle_hud", flags = ConVarFlags.None, helpText = Lang.TOGGLEHUD_HELP)] + public static void CCToggleHUD(ConCommandArgs args) { RoR2.UI.HUD.cvHudEnable.SetBool(!RoR2.UI.HUD.cvHudEnable.value); Log.MessageNetworked(String.Format(RoR2.UI.HUD.cvHudEnable.value ? Lang.SETTING_ENABLED : Lang.SETTING_DISABLED, "Hud"), args); @@ -890,12 +889,11 @@ public static void CC_ToggleHUD(ConCommandArgs args) [ConCommand(commandName = "reset_stats", flags = ConVarFlags.SenderMustBeServer, helpText = Lang.RESETSTAT_HELP)] - [ConCommand(commandName = "unset_stats", flags = ConVarFlags.SenderMustBeServer, helpText = Lang.RESETSTAT_HELP)] - [AutoComplete(Lang.TARGET_PLAYER_PINGED)] - public static void CC_ReSetStats(ConCommandArgs args) + [AutoComplete(Lang.PLAYER_OR_PINGED)] + public static void CCResetSetStats(ConCommandArgs args) { args.userArgs.Insert(0,""); - CC_SetStats(args); + CCSetStats(args); } //Idk how these work with client to server @@ -909,7 +907,7 @@ public static void CC_ReSetStats(ConCommandArgs args) [ConCommand(commandName = "set_movespeed", flags = ConVarFlags.SenderMustBeServer, helpText = Lang.SETSTAT_HELP)] [ConCommand(commandName = "set_jumppower", flags = ConVarFlags.SenderMustBeServer, helpText = Lang.SETSTAT_HELP)] [AutoComplete(Lang.SETSTATS_ARGS)] - public static void CC_SetStats(ConCommandArgs args) + public static void CCSetStats(ConCommandArgs args) { if (!Run.instance) { @@ -927,11 +925,6 @@ public static void CC_SetStats(ConCommandArgs args) Log.MessageNetworked(target.failMessage, args, LogLevel.MessageClientOnly); return; } - if (!target.body) - { - Log.MessageNetworked("No target body found", args, LogLevel.MessageClientOnly); - return; - } if (!TextSerialization.TryParseInvariant(args[0], out float amount)) { Log.MessageNetworked(string.Format(Lang.PARSE_ERROR, "amount", "float"), args, LogLevel.MessageClientOnly); @@ -1040,6 +1033,8 @@ public static void SetStatsForBody(CharacterBody body, Stat stat, float amount) body.levelDamage = ogBody.levelDamage; body.baseAttackSpeed = ogBody.baseAttackSpeed; body.levelAttackSpeed = ogBody.levelAttackSpeed; + body.baseCrit = ogBody.baseCrit; + body.levelCrit = ogBody.levelCrit; // body.baseMaxHealth = ogBody.baseMaxHealth; body.levelMaxHealth = ogBody.levelMaxHealth; @@ -1051,38 +1046,12 @@ public static void SetStatsForBody(CharacterBody body, Stat stat, float amount) body.baseMoveSpeed = ogBody.baseMoveSpeed; body.levelMoveSpeed = ogBody.levelMoveSpeed; body.baseAcceleration = ogBody.baseAcceleration; - body.level = ogBody.levelMoveSpeed; body.baseJumpPower = ogBody.baseJumpPower; body.levelJumpPower = ogBody.levelJumpPower; break; } body.MarkAllStatsDirty(); } - - [ConCommand(commandName = "set_health", flags = ConVarFlags.ExecuteOnServer, helpText = "Sets health to specifiedd amount and removes regen for testing.")] - public static void CC_SetHP(ConCommandArgs args) - { - if (!args.senderMaster) - { - return; - } - if (!args.senderMaster.GetBody()) - { - //WolfoLib.log.LogMessage("No Body"); - return; - } - float newDamage = (float)System.Convert.ToInt16(args[0]); - var body = args.senderMaster.GetBody(); - body.baseMaxHealth = newDamage; - body.levelMaxHealth = 0; - body.maxHealth = newDamage; - body.baseRegen = 0; - body.levelRegen = 0; - body.regen = 0; - - body.healthComponent.health = body.maxHealth; - } - - + } } diff --git a/Code/DT-Commands/Spawners.cs b/Code/DT-Commands/Spawners.cs index d542318..250b981 100644 --- a/Code/DT-Commands/Spawners.cs +++ b/Code/DT-Commands/Spawners.cs @@ -14,7 +14,6 @@ namespace DebugToolkit.Commands class Spawners { private static readonly Dictionary portals = new Dictionary(); - [ConCommand(commandName = "spawn_interactable", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.SPAWNINTERACTABLE_HELP)] [ConCommand(commandName = "spawn_interactible", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.SPAWNINTERACTABLE_HELP)] [AutoComplete(Lang.SPAWNINTERACTABLE_ARGS)] @@ -46,7 +45,12 @@ private static void CCSpawnInteractable(ConCommandArgs args) Log.MessageNetworked(Lang.INTERACTABLE_NOTFOUND, args, LogLevel.MessageClientOnly); return; } - int amount = args.TryGetArgInt(1).GetValueOrDefault(1); + int amount = 1; + if (args.Count > 1 && args[1] != Lang.DEFAULT_VALUE && !TextSerialization.TryParseInvariant(args[1], out amount)) + { + Log.MessageNetworked(String.Format(Lang.PARSE_ERROR, "count", "int"), args, LogLevel.MessageClientOnly); + return; + } // Putting interactables with a collider just far enough to not cause any clipping // or spawn under the character's feet. The few exceptions with MeshCollider aren't // treated but they aren't much of an issue. @@ -82,11 +86,6 @@ private static void CCSpawnInteractable(ConCommandArgs args) var direction = args.senderBody.inputBank.aimDirection; position = position + (args.senderBody.radius + distance) * new Vector3(direction.x, 0f, direction.z); } - if (amount > 100) - { - amount = 100; - Log.MessageNetworked($"Limited to 100, please don't spawn too many things at once.", args, LogLevel.MessageClientOnly); - } int failed = 0; for (int i = 0; i < amount; i++) { @@ -207,11 +206,6 @@ private static void CCSpawnAI(ConCommandArgs args) Log.MessageNetworked(String.Format(Lang.PARSE_ERROR, "count", "int"), args, LogLevel.MessageClientOnly); return; } - if (amount > 100) - { - amount = 100; - Log.MessageNetworked($"Limited to 100, please dont spawn too many things at once.", args, LogLevel.MessageClientOnly); - } EliteDef eliteDef = null; if (args.Count > 2 && args[2] != Lang.DEFAULT_VALUE) { diff --git a/Code/DebugToolkit.cs b/Code/DebugToolkit.cs index f9ec603..b950d29 100644 --- a/Code/DebugToolkit.cs +++ b/Code/DebugToolkit.cs @@ -73,6 +73,7 @@ private void LogBuildInfo() private void Start() { var _ = StringFinder.Instance; + RoR2Application.onLoad += AutoCompleteManager.RegisterAutoCompleteCommands; } private void Update() diff --git a/Code/Hooks.cs b/Code/Hooks.cs index b4cc86b..814bc46 100644 --- a/Code/Hooks.cs +++ b/Code/Hooks.cs @@ -29,6 +29,7 @@ public sealed class Hooks public static bool buddha; public static bool buddhaMonsters; public static bool god; + public static bool godMonsters; private static GameObject commandSignatureText; private static CombatDirector bossDirector; @@ -59,7 +60,7 @@ public static void InitializeHooks() On.RoR2.Console.AutoComplete.SetSearchString += BetterAutoCompletion; RoR2Application.onLoad += Items.InitDroptableData; RoR2Application.onLoad += Spawners.InitPortals; - RoR2Application.onLoad += AutoCompleteManager.RegisterAutoCompleteCommands; + Run.onRunStartGlobal += Items.CollectItemTiers; On.RoR2.UI.ConsoleWindow.Start += AddConCommandSignatureHint; On.RoR2.UI.ConsoleWindow.OnInputFieldValueChanged += UpdateCommandSignature; @@ -159,20 +160,9 @@ private static void SetBuddhaMode(On.RoR2.CharacterBody.orig_Start orig, Charact if (buddha) { self.bodyFlags |= CharacterBody.BodyFlags.Buddha; - } - /*if (PlayerCommands.NoCooldowns) - { - GenericSkill[] slots = self.GetComponents(); - foreach (GenericSkill slot in slots) - { - if (slot.finalRechargeInterval != 0) - { - slot.cooldownOverride = 0.001f; - } - } - }*/ + } } - else if(buddhaMonsters) + else if(buddhaMonsters && self.teamComponent && (self.teamComponent.teamIndex == TeamIndex.Monster || self.teamComponent.teamIndex == TeamIndex.Void)) { self.bodyFlags |= CharacterBody.BodyFlags.Buddha; } @@ -233,6 +223,7 @@ private static void SetGodMode(On.RoR2.CharacterMaster.orig_Awake orig, Characte if (NetworkServer.active) { self.godMode |= self.playerCharacterMasterController && god; + self.godMode |= self.teamIndex == TeamIndex.Monster && godMonsters; } } @@ -392,10 +383,9 @@ void ExpandHelpText(BaseConVar cv, string text) RemoveCheatFlag(self.FindConVar("bag_disable_breakout")); RemoveCheatFlag(self.FindConVar("bounce_velocity")); RemoveCheatFlag(self.FindConVar("junk_unlimited")); - RemoveCheatFlag(self.FindConVar("timescale")); const string MOD_MESSAGE = " Let the DebugToolkit team know if you need this convar."; - //ExpandHelpText(self.FindConVar("timescale"), " Use time_scale instead!"); + ExpandHelpText(self.FindConVar("timescale"), " Use time_scale instead!"); ExpandHelpText(self.FindConVar("director_combat_disable"), " Use no_enemies instead!"); ExpandHelpText(self.FindConVar("timestep"), MOD_MESSAGE); ExpandHelpText(self.FindConVar("cmotor_safe_collision_step_threshold"), MOD_MESSAGE); diff --git a/Code/Lang.cs b/Code/Lang.cs index 6b541d4..c33f339 100644 --- a/Code/Lang.cs +++ b/Code/Lang.cs @@ -12,7 +12,7 @@ public const string BIND_DELETE_ARGS = "Requires 1 argument: {key}", CHANGETEAM_ARGS = "Requires 1 (2 if from server) argument: {team} [player:]", CHARGEZONE_ARGS = "Requires 1 argument: {charge}", - CREATEPICKUP_ARGS = "Requires 1 (3 if from server) argument: {object (item|equip|drone|'lunarcoin'|'voidcoin')} [search ('item'|'equip'|'drone'|'all'|'pickup'):'all'] [itemTypesNoChanneled:'permanent'] player:]", + CREATEPICKUP_ARGS = "Requires 1 (3 if from server) argument: {object (item|equip|drone|'lunarcoin'|'voidcoin')} [search ('item'|'equip'|'drone'|'all'|'pickup'):'all'] [pickup_type:'permanent'] player:]", CREATEPOTENTIAL_ARGS = "Requires 0 (3 if from server) arguments: [droptable (droptable|'all'):'all'] [count:3] *[player:]", DELAY_ARGS = "Requires 2 arguments: {delay} {console_commands}", DUMPSTATE_ARGS = "Requires 0 (1 if from server) argument: [target (player|'pinged'):]", @@ -24,21 +24,22 @@ public const string GIVEDOT_ARGS = "Requires 1 (4 if from server) argument: {dot} [count:1] [target (player|'pinged'):] [attacker (player|'pinged'):]", GIVEEQUIP_ARGS = "Requires 1 (2 if from server) argument: {equip (equip|'random')} [target (player|'pinged'|'evolution'|'simulacrum'|'voidfields'|'devotion'):]", RANDOMEQUIP_ARGS = "Requires 0 (1 if from server) argument: [target (player|'pinged'):]", - //GIVEITEM_ARGS = "Requires 1 (3 if from server) argument: {item} [count:1] [type ('permanent'|'temp'|'channeled'):'permanent'] [target (player|'pinged'|'evolution'|'simulacrum'|'voidfields'|'devotion'):]", - GIVEITEM_ARGS = "Requires 1 (3 if from server) argument: {item} [count:1] [itemTypes:'permanent'] [target (player|'pinged'|'evolution'|'simulacrum'|'voidfields'|'devotion'):]", - GIVEDRONE_ARGS = "Requires 1 (2 if from server) argument: {drone} [count:1] [droneTier:1] [target (player|'pinged'):]", + GIVEITEM_ARGS = "Requires 1 (3 if from server) argument: {item} [count:1] [item_type:'permanent'] [target (player|'pinged'|'evolution'|'simulacrum'|'voidfields'|'devotion'):]", + GIVEDRONE_ARGS = "Requires 1 (4 if from server) argument: {drone} [count:1] [droneTier:1] [target (player|'pinged'):]", + REMOVEALLDRONES_ARGS = "Requires 0 (1 if from server) argument: [target (player|'pinged'):]", GIVELUNAR_ARGS = "Requires 0 arguments: [amount:1]", GIVEMONEY_ARGS = "Requires 1 argument: {amount} [target (player|'all')]", - MONEY_ARGS = "Requires 0 argument: [target (player|'all')]", + PLAYER_OR_ALL_OPTIONAL_ARGS = "Requires 0 argument: [target (player|'all'):]", + PLAYER_OR_ALL_ARGS = "Requires 1 argument: {target (player|'all')}", SETSTATS_ARGS = "Requires 1 argument: {amount} [target (player|'pinged'):]", - TARGET_PLAYER_PINGED = "Requires 0 argument: [target (player|'pinged'):]", + PLAYER_OR_PINGED = "Requires 0 (1 if from server) arguments: [target (player|'pinged'):]", + PLAYERPINGED_OR_ALL = "Requires 0 (1 if from server) arguments: [target (player|'pinged'|'all'):]", HEAL_ARGS = "Requires 1 argument: {amount} [target (player|'pinged'):]", - HURT_ARGS = "Requires 1 argument: {amount} [target (player|'pinged'):] [bypassCalcs (0|1):0/false]", - KICK_ARGS = "Requires 1 argument: {player}", - KILLALL_ARGS = "Requires 0 arguments: [team:Monster&Void], [trueKill (0|1):0/false]", + HURT_ARGS = "Requires 1 argument: {amount} [target (player|'pinged'):] [direct (0|1):0/false]", + PLAYER_ARGS = "Requires 1 argument: {player}", + KILLALL_ARGS = "Requires 0 arguments: [team:Monster&Void]", LISTSKIN_ARGS = "Requires 0 arguments: [selection (body|'all'|'body'|'self'):'all']", LISTQUERY_ARGS = "Requires 0 arguments: [query]", - LISTMODS_ARGS = "Requires 0 arguments: [filterByRequiredByAll (0'both'|1'yes'|2'no'):0]", LOADOUTSKIN_ARGS = "Requires 2 argument: {body_name (body|'self')} {skin_index}", LOADOUTSKILL_ARGS = "Requires 2 argument: {skill_slot} {skill_variant}", NEXTBOSS_ARGS = "Requires 1 argument: {director_card} [count:1] [elite:None]", @@ -46,8 +47,7 @@ public const string NO_ARGS = "Requires 0 arguments.", PERM_MOD_ARGS = "Requires 2 arguments: {permission_level} {player}", POSTSOUNDEVENT_ARGS = "Requires 1 argument: {sound_event (event_name|event_id)}", - RANDOMITEM_ARGS = "Requires 1 (3 if from server) argument: {count} [tier (tier|'all'):'\"0,1,2,4\"'] [itemTypes:'permanent'] [target (player|'pinged'|'evolution'|'simulacrum'|'voidfields'|'devotion'):]", - RANDOMITEM2_ARGS = "Requires 1 (3 if from server) argument: {count} [allowLunar (0|1):0/false] [allowVoid (0|1):0/false] [target (player|'pinged'|'evolution'|'simulacrum'|'voidfields'|'devotion'):]", + RANDOMITEM_ARGS = "Requires 1 (3 if from server) argument: {count} [droptable (droptable|'all'):'\"0,1,2,4\"'] [itemTypes:'permanent'] [target (player|'pinged'|'evolution'|'simulacrum'|'voidfields'|'devotion'):]", REMOVEALLBUFFS_ARGS = "Requires 0 (2 if from server) arguments: [timed (0|1):0/false] [target (player|'pinged'):]", REMOVEALLDOTS_ARGS = "Requires 0 (1 if from server) arguments: [target (player|'pinged'):]", REMOVEALLITEMS_ARGS = "Requires 0 (1 if from server) arguments: [target (player|'pinged'|'evolution'|'simulacrum'|'voidfields'|'devotion'):]", @@ -63,12 +63,11 @@ public const string SEED_ARGS = "Requires 0 or 1 argument: [new_seed]", SETARTIFACT_ARGS = "Requires 1 (2 if using 'all') argument: {artifact (artifact|'all')} [enable (0|1)]", SPAWNAI_ARGS = "Requires 1 argument: {ai} [count:1] [elite:None] [braindead (0|1):0/false] [team (team|'ally'):Monster]", - SPAWNAS_ARGS = "Requires 1 (3 if from server) argument: {body} [permanent (0|1):1/true] [player:]", + SPAWNAS_ARGS = "Requires 1 (2 if from server) argument: {body} [player:]", SPAWNBODY_ARGS = "Requires 1 argument: {body}", SPAWNINTERACTABLE_ARGS = "Requires 1 argument: {interactable} [count:1]", SPAWNPORTAL_ARGS = "Requires 1 argument: {portal ('artifact'|'blue'|'celestial'|'deepvoid'|'gold'|'green'|'null'|'void')}", - TIMESCALE_ARGS = "Requires 1 argument: {time_scale}", - TRUEKILL_ARGS = "Requires 0 (1 if from server) arguments: [player:]" + TIMESCALE_ARGS = "Requires 1 argument: {time_scale}" ; // Command help texts @@ -80,7 +79,7 @@ public const string BIND_RELOAD_HELP = "Reload the macro system of DebugToolkit. " + NO_ARGS, //BUDDHA_HELP = "Become immortal. Instead of refusing damage you just refuse to take lethal damage.\nIt works by giving all damage a player takes DamageType.NonLethal. " + ENABLE_ARGS, BUDDHA_HELP = "Players become immortal, but remain attackable. " + ENABLE_ARGS, - BUDDHA_HELP2 = "Enemies become immortal, but remain attackable. " + ENABLE_ARGS, + BUDDHAENEMY_HELP = "Enemies become immortal, but remain attackable. " + ENABLE_ARGS, CHANGETEAM_HELP = "Change the specified player to the specified team. " + CHANGETEAM_ARGS, CHARGEZONE_HELP = "Set the charge of all active holdout zones. " + CHARGEZONE_ARGS, CREATEPICKUP_HELP = "Creates a PickupDroplet infront of your position. " + CREATEPICKUP_ARGS, @@ -92,6 +91,8 @@ public const string DUMPINVENTORIES_HELP = "List the inventory items and equipment of all spawned bodies. " + NO_ARGS, DUMPSTATE_HELP = "List the current stats, entity state, and skill cooldown of a specified body. " + DUMPSTATE_ARGS, DUMPSTATS_HELP = "List the base stats of a specific body. " + DUMPSTATS_ARGS, + DUMPMODS_HELP = "Lists installed mods and mods that are required by everyone." + NO_ARGS, + EVOLVE_LEMURIAN_HELP = "Triggers evolution for Artifact of Devotion Lemurians." + PLAYER_OR_ALL_OPTIONAL_ARGS, FAMILYEVENT_HELP = "Forces a family event to occur during the next stage. " + NO_ARGS, FIXEDTIME_HELP = "Sets the run timer to the specified value. " + FIXEDTIME_ARGS, FORCEWAVE_HELP = "Set the next wave prefab. Leave empty to see all options. " + FORCEWAVE_ARGS, @@ -101,20 +102,21 @@ public const string RANDOMEQUIP_HELP = "Gives a random equipment to a target. " + RANDOMEQUIP_ARGS, GIVEITEM_HELP = "Gives the specified item to a target. " + GIVEITEM_ARGS, GIVEDRONE_HELP = "Summons the specified drone to a target. " + GIVEDRONE_ARGS, - REMOVEALLDRONES_HELP = "Removes all drones from the target. " + KICK_ARGS, - KILL_ALL_MINIONS_HELP = "Kills all minions owned by target. " + KICK_ARGS, + REMOVEALLDRONES_HELP = "Removes all drones from the target. " + REMOVEALLDRONES_ARGS, + KILL_ALL_MINIONS_HELP = "Kills all minions owned by target. " + REMOVEALLDRONES_ARGS, GIVELUNAR_HELP = "Gives amount of lunar coin to you. " + GIVELUNAR_ARGS, GIVEVOID_HELP = "Gives amount of void markers to you. " + GIVELUNAR_ARGS, GIVEMONEY_HELP = "Gives the specified amount of money to the specified player. " + GIVEMONEY_ARGS, NO_MONEY_HELP = "Sets money to 0 for specified player. " + GIVEMONEY_ARGS, ALLMONEY_HELP = "Sets money to 2'000'000'000 for specified player. " + GIVEMONEY_ARGS, GOD_HELP = "Become invincible. " + ENABLE_ARGS, + GODENEMY_HELP = "All monster team members become invincible. " + ENABLE_ARGS, SETSTAT_HELP = "Sets the base stat to a specific value for yourself or target, and the level stat to 0. " + SETSTATS_ARGS, RESETSTAT_HELP = "Resets the base & level stats for yourself or target", HEAL_HELP = "Heal yourself or another target. " + HEAL_ARGS, HURT_HELP = "Deal generic damage to yourself or another target. " + HURT_ARGS, - KICK_HELP = "Kicks the specified player from the session. " + KICK_ARGS, + KICK_HELP = "Kicks the specified player from the session. " + PLAYER_ARGS, KILLALL_HELP = "Kill all entities on the specified team. " + KILLALL_ARGS, LISTAI_HELP = "List all Masters and their language invariants. " + LISTQUERY_ARGS, LISTARTIFACT_HELP = "List all Artifacts and their language invariants. " + LISTQUERY_ARGS, @@ -136,7 +138,7 @@ public const string LISTTEAM_HELP = "List all Teams and their language invariants. " + LISTQUERY_ARGS, LOADOUTSKIN_HELP = "Change your loadout's skin. " + LOADOUTSKIN_ARGS, LOCKEXP_HELP = "Prevent Experience gain. " + ENABLE_ARGS, - NOCOOLDOWN_HELP = "Toggles skill cooldowns of the target. " + TARGET_PLAYER_PINGED, + NOCOOLDOWN_HELP = "Toggles skill cooldowns of the target. " + PLAYER_OR_PINGED, MACRO_DTPEACE_HELP = "Kills all enemies, voids and disables enemies spawning.", MACRO_DTZOOM_HELP = "Gives you 20 hooves and 200 feathers for getting around quickly.", MACRO_DTDAMAGE_HELP = "Gives you a lot of BoostDamage hidden item.", @@ -179,24 +181,24 @@ public const string SPAWNPORTAL_HELP = "Spawns a portal in front of the player. " + SPAWNPORTAL_ARGS, STOPTIMER_HELP = "Pause/unpause the run timer. " + ENABLE_ARGS, TIMESCALE_HELP = "Sets the Time Delta. " + TIMESCALE_ARGS, - TRUEKILL_HELP = "Kill the entity bypassing revives, buddha & godmode . " + TRUEKILL_ARGS, - TOGGLETIME_HELP = "Toggles timescale between 0 and normal value. " + TRUEKILL_HELP = "Kill the entity bypassing revives, buddha & godmode. " + PLAYERPINGED_OR_ALL, + TOGGLETIME_HELP = "Toggles timescale between 0 and normal value. " + NO_ARGS, + TOGGLEMODE_HELP = "Turn off your model for screenshots" + NO_ARGS, + TOGGLEHUD_HELP = "Toggle hud_enable. Enable/disable the HUD." + NO_ARGS ; // Messages public const string - CREATEPICKUP_AMBIGIOUS_4 = "Found multiple results. Please be more precise or specify using 'item', 'equip', 'drone'\n{0}", - //CREATEPICKUP_AMBIGIOUS_3 = "Could not choose between {0}\n{1}\n{2}, please be more precise. Specify in second argument using 'item', 'equip' or 'drone'", - //CREATEPICKUP_AMBIGIOUS_2 = "Could not choose between {0}\n{1}, please be more precise. Specify in second argument using 'item', 'equip' or 'drone'", + CREATEPICKUP_AMBIGIOUS = "Found multiple results. Please be more precise or specify using 'item', 'equip', 'drone'\n{0}", CREATEPICKUP_NOTFOUND = "Could not find any item, equipment or drone with that name or index.", CREATEPICKUP_SUCCESS_1 = "Successfully created the pickup {0}.", CREATEPICKUP_SUCCESS_2 = "Successfully created a potential with {0} options.", GIVELUNAR_2 = "{0} {1} lunar coin(s).", GIVEVOIDC_2 = "{0} {1} void marker(s).", - GIVEITEM = "Gave {0} {1} to {2}.", //Amount ItemType Item Target - GIVEBUFF = "Gave {0} {1} to {2}.", + GIVEOBJECT = "Gave {0} {1} to {2}.", GIVEDRONE = "Summoned {0} {1} (Tier {3}) to {2}.", REMOVEDRONES = "Removed {0} drones from {1}.", + REMOVEDEQUIP = "Removed current Equipment from {0}.", Kill_MINIONS = "Killed all minions owned by {0}.", OBSOLETEWARNING = "This command has become obsolete and will be removed in the next version. ", NETWORKING_OTHERPLAYER_4 = "{0}({1}) issued: {2} {3}", diff --git a/Code/StringFinder.cs b/Code/StringFinder.cs index e3afe78..72ba03d 100644 --- a/Code/StringFinder.cs +++ b/Code/StringFinder.cs @@ -6,7 +6,6 @@ using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.ResourceManagement.AsyncOperations; -using UnityEngine.UI; namespace DebugToolkit { @@ -40,7 +39,7 @@ private StringFinder() private static void GatherCSCs() { - GatherAddressableAssets("/csc", (asset) => + /*GatherAddressableAssets("/csc", (asset) => { characterSpawnCard.Add(new DirectorCard { @@ -50,14 +49,46 @@ private static void GatherCSCs() preventOverhead = true, spawnDistance = DirectorCore.MonsterSpawnDistance.Standard, }); - }); + });*/ + + RoR2Application.onLoad += () => + { + //I imagine this would fail to get modded MultiCSC + var CSCList = Resources.FindObjectsOfTypeAll(typeof(CharacterSpawnCard)) as CharacterSpawnCard[]; + + foreach (var resourceLocator in Addressables.ResourceLocators) + { + foreach (var key in resourceLocator.Keys) + { + var keyString = key.ToString(); + if (keyString.Contains("/csc")) + { + characterSpawnCard.Add(new DirectorCard + { + spawnCard = Addressables.LoadAssetAsync(keyString).WaitForCompletion(), + preventOverhead = true, + }); + } + } + } + + var filteredList = + CSCList.Where(spawnCard => spawnCard is CharacterSpawnCard && characterSpawnCard.All(existingCSC => existingCSC.spawnCard.name != spawnCard.name)); + foreach (var card in filteredList) + { + characterSpawnCard.Add(new DirectorCard + { + spawnCard = card, + preventOverhead = true, + }); + } + }; + + } private void GatherISCs() { - //GatherAddressableAssets("/isc", (asset) => interactableSpawnCards.Add(asset)); - //On.RoR2.ClassicStageInfo.Start += AddCurrentStageIscsToCache; - RoR2Application.onLoad += () => { //Doing this first means only getting loaded spawn cards. @@ -386,11 +417,21 @@ public ItemIndex GetItemFromPartial(string name) return GetItemsFromPartial(name).DefaultIfEmpty(ItemIndex.None).First(); } + /// + /// Returns an DroneIndex when provided with an index or partial/invariant. + /// + /// Matches either the exact (int)Index or Partial Invariant + /// Returns the DroneIndex if a match is found, or returns DroneIndex.None public DroneIndex GetDroneFromPartial(string name) { return GetDronesFromPartial(name).DefaultIfEmpty(DroneIndex.None).First(); } + /// + /// Returns an PickupIndex when provided with an index or partial/invariant. + /// + /// Matches either the exact (int)Index or Partial Invariant + /// Returns the PickupIndex if a match is found, or returns PickupIndex.none public PickupIndex GetPickupFromPartial(string name) { return GetPickupsFromPartial(name).DefaultIfEmpty(PickupIndex.none).First(); @@ -432,6 +473,12 @@ public IEnumerable GetItemsFromPartial(string name) } } + + /// + /// Returns an iterator of DroneIndex's when provided with an index or partial/invariant. + /// + /// Matches either the exact (int)Index or Partial Invariant + /// Returns an iterator with all DroneIndex's matched public IEnumerable GetDronesFromPartial(string name) { if (TextSerialization.TryParseInvariant(name, out int i)) @@ -464,6 +511,12 @@ public IEnumerable GetDronesFromPartial(string name) } } + + /// + /// Returns an iterator of PickupIndex's when provided with an index or partial/invariant. + /// + /// Matches either the exact (int)Index or Partial Invariant + /// Returns an iterator with all PickupIndex's matched public IEnumerable GetPickupsFromPartial(string name) { if (TextSerialization.TryParseInvariant(name, out int i)) From 3d9beab05b244058597e9ae72c85f0a0cb4c3d7f Mon Sep 17 00:00:00 2001 From: Wolfo Date: Wed, 31 Dec 2025 21:14:22 +0100 Subject: [PATCH 07/25] Update PlayerCommands.cs --- Code/DT-Commands/PlayerCommands.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Code/DT-Commands/PlayerCommands.cs b/Code/DT-Commands/PlayerCommands.cs index 64b5727..15c4818 100644 --- a/Code/DT-Commands/PlayerCommands.cs +++ b/Code/DT-Commands/PlayerCommands.cs @@ -876,15 +876,14 @@ public static void CCToggleModel(ConCommandArgs args) GameObject mdl = args.senderBody.GetComponent().modelTransform.gameObject; mdl.SetActive(!mdl.activeSelf); Log.MessageNetworked(String.Format(!mdl.activeSelf ? Lang.SETTING_ENABLED : Lang.SETTING_DISABLED, "Invisible Model"), args); - + Log.MessageNetworked(String.Format(RoR2.UI.HUD.cvHudEnable.value ? Lang.SETTING_ENABLED : Lang.SETTING_DISABLED, "Hidden Model"), args, LogLevel.MessageClientOnly); } [ConCommand(commandName = "toggle_hud", flags = ConVarFlags.None, helpText = Lang.TOGGLEHUD_HELP)] public static void CCToggleHUD(ConCommandArgs args) { - RoR2.UI.HUD.cvHudEnable.SetBool(!RoR2.UI.HUD.cvHudEnable.value); - Log.MessageNetworked(String.Format(RoR2.UI.HUD.cvHudEnable.value ? Lang.SETTING_ENABLED : Lang.SETTING_DISABLED, "Hud"), args); - + RoR2.UI.HUD.cvHudEnable.SetBool(!RoR2.UI.HUD.cvHudEnable.value); + Log.MessageNetworked(String.Format(RoR2.UI.HUD.cvHudEnable.value ? Lang.SETTING_ENABLED : Lang.SETTING_DISABLED, "Hud"), args, LogLevel.MessageClientOnly); } From 5edebd314543a097d89920008c5e0a48c8fc28b2 Mon Sep 17 00:00:00 2001 From: Wolfo Date: Wed, 31 Dec 2025 21:26:04 +0100 Subject: [PATCH 08/25] 'give_buff' negative amount now just calls 'remove_buff' cleaner code this way. also added same support for 'remove_buff' --- CHANGELOG.md | 3 +- Code/DT-Commands/Buffs.cs | 50 +++++++++++------------------- Code/DT-Commands/Drones.cs | 4 +-- Code/DT-Commands/PlayerCommands.cs | 1 - Code/Lang.cs | 2 +- 5 files changed, 23 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c7c556..609589a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,7 +45,7 @@ * 'create_pickup' now supports dropping drones & pickups. * 'create_pickup' switched {search} and {permanent/temp} argument spots. * 'give_equip -1' now removes your equipment. - * 'give_buff' now works with negative amount for removing. + * 'give_buff' & 'remove_buff' now accept negative amounts to remove/give. * 'loadout_set_skill_variant' now accepts 'self' * 'random_items' changed default value to not give Lunars & Voids. * 'hurt' third optional argument to bypass armor&damage calculations. @@ -59,6 +59,7 @@ ### 3.21 ### + * **3.21.1** * Fixed the cheat ConVars not getting unlocked. * Also enabled the following Alloyed Collective ConVars: `bag_disable_breakout`, `bounce_velocity`, `junk_unlimited` diff --git a/Code/DT-Commands/Buffs.cs b/Code/DT-Commands/Buffs.cs index 28f9242..cc9ec07 100644 --- a/Code/DT-Commands/Buffs.cs +++ b/Code/DT-Commands/Buffs.cs @@ -88,8 +88,13 @@ private static void CCGiveBuff(ConCommandArgs args) Log.MessageNetworked(String.Format(Lang.PARSE_ERROR, "count", "int"), args, LogLevel.MessageClientOnly); return; } - bool remove = iCount < 0; - + if (iCount < 0) + { + args.userArgs[1] = (-iCount).ToString(); + CCRemoveBuff(args); + return; + } + float duration = 0f; if (args.Count > 2 && args[2] != Lang.DEFAULT_VALUE && !TextSerialization.TryParseInvariant(args[2], out duration)) { @@ -123,46 +128,26 @@ private static void CCGiveBuff(ConCommandArgs args) var canStack = BuffCatalog.GetBuffDef(buff).canStack; var body = target.body; if (duration == 0f) - { - if (remove) + { + if (!canStack) { - for (int i = 0; i > iCount; i--) - { - body.RemoveBuff(buff); - } + iCount = Math.Min(iCount, 1 - body.GetBuffCount(buff)); } - else + for (int i = 0; i < iCount; i++) { - if (!canStack) - { - iCount = Math.Min(iCount, 1 - body.GetBuffCount(buff)); - } - for (int i = 0; i < iCount; i++) - { - body.AddBuff(buff); - } + body.AddBuff(buff); } Log.MessageNetworked(string.Format(Lang.GIVEOBJECT, iCount, name, target.name, ""), args); } else { - if (remove) + if (!canStack) { - for (int i = 0; i > iCount; i--) - { - body.RemoveOldestTimedBuff(buff); - } + iCount = Math.Min(iCount, 1); } - else + for (int i = 0; i < iCount; i++) { - if (!canStack) - { - iCount = Math.Min(iCount, 1); - } - for (int i = 0; i < iCount; i++) - { - body.AddTimedBuff(buff, duration); - } + body.AddTimedBuff(buff, duration); } Log.MessageNetworked($"Gave {iCount} {name} to {target.name} for {duration} seconds", args); } @@ -192,7 +177,8 @@ private static void CCRemoveBuff(ConCommandArgs args) } if (iCount < 0) { - Log.MessageNetworked(String.Format(Lang.NEGATIVE_ARG, "count"), args, LogLevel.MessageClientOnly); + args.userArgs[1] = (-iCount).ToString(); + CCGiveBuff(args); return; } diff --git a/Code/DT-Commands/Drones.cs b/Code/DT-Commands/Drones.cs index 7d7eb69..5e2382e 100644 --- a/Code/DT-Commands/Drones.cs +++ b/Code/DT-Commands/Drones.cs @@ -55,12 +55,12 @@ private static void CCGiveDrone(ConCommandArgs args) int tier = 1; if (args.Count > 2 && args[2] != Lang.DEFAULT_VALUE && !TextSerialization.TryParseInvariant(args[2], out tier)) { - Log.MessageNetworked(String.Format(Lang.PARSE_ERROR, "drone_tier", "int"), args, LogLevel.MessageClientOnly); + Log.MessageNetworked(String.Format(Lang.PARSE_ERROR, "droneTier", "int"), args, LogLevel.MessageClientOnly); return; } if (tier < 0) { - Log.MessageNetworked(string.Format(Lang.NEGATIVE_ARG, "drone_tier"), args, LogLevel.MessageClientOnly); + Log.MessageNetworked(string.Format(Lang.NEGATIVE_ARG, "droneTier"), args, LogLevel.MessageClientOnly); return; } diff --git a/Code/DT-Commands/PlayerCommands.cs b/Code/DT-Commands/PlayerCommands.cs index 15c4818..7deb917 100644 --- a/Code/DT-Commands/PlayerCommands.cs +++ b/Code/DT-Commands/PlayerCommands.cs @@ -875,7 +875,6 @@ public static void CCToggleModel(ConCommandArgs args) } GameObject mdl = args.senderBody.GetComponent().modelTransform.gameObject; mdl.SetActive(!mdl.activeSelf); - Log.MessageNetworked(String.Format(!mdl.activeSelf ? Lang.SETTING_ENABLED : Lang.SETTING_DISABLED, "Invisible Model"), args); Log.MessageNetworked(String.Format(RoR2.UI.HUD.cvHudEnable.value ? Lang.SETTING_ENABLED : Lang.SETTING_DISABLED, "Hidden Model"), args, LogLevel.MessageClientOnly); } diff --git a/Code/Lang.cs b/Code/Lang.cs index c33f339..86a0d14 100644 --- a/Code/Lang.cs +++ b/Code/Lang.cs @@ -47,7 +47,7 @@ public const string NO_ARGS = "Requires 0 arguments.", PERM_MOD_ARGS = "Requires 2 arguments: {permission_level} {player}", POSTSOUNDEVENT_ARGS = "Requires 1 argument: {sound_event (event_name|event_id)}", - RANDOMITEM_ARGS = "Requires 1 (3 if from server) argument: {count} [droptable (droptable|'all'):'\"0,1,2,4\"'] [itemTypes:'permanent'] [target (player|'pinged'|'evolution'|'simulacrum'|'voidfields'|'devotion'):]", + RANDOMITEM_ARGS = "Requires 1 (3 if from server) argument: {count} [droptable (droptable|'all'):'\"Tier1:100,Tier2:60,Tier3:4\"'] [itemTypes:'permanent'] [target (player|'pinged'|'evolution'|'simulacrum'|'voidfields'|'devotion'):]", REMOVEALLBUFFS_ARGS = "Requires 0 (2 if from server) arguments: [timed (0|1):0/false] [target (player|'pinged'):]", REMOVEALLDOTS_ARGS = "Requires 0 (1 if from server) arguments: [target (player|'pinged'):]", REMOVEALLITEMS_ARGS = "Requires 0 (1 if from server) arguments: [target (player|'pinged'|'evolution'|'simulacrum'|'voidfields'|'devotion'):]", From 1867d7dc3f2c29eaac1fa334dc6c19747429a832 Mon Sep 17 00:00:00 2001 From: Wolfo Date: Wed, 31 Dec 2025 21:42:06 +0100 Subject: [PATCH 09/25] cleanse now a proper macro not rather duplicate code calls the other commands now. Apparently 'removed_all_buffs 0' is also just broken with ss2 at least with beta. Not sure what to do about that --- Code/DT-Commands/Buffs.cs | 39 ++------------------------------------ Code/DT-Commands/Macros.cs | 8 ++++++++ Code/Lang.cs | 2 ++ 3 files changed, 12 insertions(+), 37 deletions(-) diff --git a/Code/DT-Commands/Buffs.cs b/Code/DT-Commands/Buffs.cs index cc9ec07..1e9cf12 100644 --- a/Code/DT-Commands/Buffs.cs +++ b/Code/DT-Commands/Buffs.cs @@ -137,7 +137,7 @@ private static void CCGiveBuff(ConCommandArgs args) { body.AddBuff(buff); } - Log.MessageNetworked(string.Format(Lang.GIVEOBJECT, iCount, name, target.name, ""), args); + Log.MessageNetworked(string.Format(Lang.GIVEOBJECT, iCount, name, target.name), args); } else { @@ -297,42 +297,7 @@ private static void CCRemoveBuffStacks(ConCommandArgs args) } - [ConCommand(commandName = "cleanse", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.REMOVEALLBUFFS_HELP)] - private static void CCCleanse(ConCommandArgs args) - { - if (!Run.instance) - { - Log.MessageNetworked(Lang.NOTINARUN_ERROR, args, LogLevel.MessageClientOnly); - return; - } - bool isDedicatedServer = args.sender == null; - if (isDedicatedServer && (args.Count < 1 || args[0] == Lang.DEFAULT_VALUE)) - { - Log.MessageNetworked(Lang.INSUFFICIENT_ARGS + Lang.REMOVEALLBUFFS_ARGS, args, LogLevel.MessageClientOnly); - return; - } - - - var target = ParseTarget(args, 1); - if (target.failMessage != null) - { - Log.MessageNetworked(target.failMessage, args, LogLevel.MessageClientOnly); - return; - } - - var body = target.body; - if (!body) - { - Log.MessageNetworked(target.failMessage, args, LogLevel.MessageClientOnly); - return; - } - CleanseSystem.CleanseBodyServer(body, true, true, true, true, true, false); - for (int i = 0; i < BuffCatalog.buffCount; i++) - { - body.SetBuffCount((BuffIndex)i, 0); - } - Log.MessageNetworked($"Cleansed {target.name} of all buffs.", args); - } + [ConCommand(commandName = "remove_all_buffs", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.REMOVEALLBUFFS_HELP)] [AutoComplete(Lang.REMOVEALLBUFFS_ARGS)] diff --git a/Code/DT-Commands/Macros.cs b/Code/DT-Commands/Macros.cs index 3dc3dd0..4609a31 100644 --- a/Code/DT-Commands/Macros.cs +++ b/Code/DT-Commands/Macros.cs @@ -58,6 +58,14 @@ private static void Damage(ConCommandArgs args) Invoke(args.sender, "give_item", "boostdamage", "9999990"); } + [ConCommand(commandName = "dtcleanse", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.MACRO_DTCLEANSE_HELP)] + private static void CCCleanse(ConCommandArgs args) + { + Macros.Invoke(args.sender, "remove_all_buffs"); + Macros.Invoke(args.sender, "remove_all_buffs", "1"); + Macros.Invoke(args.sender, "remove_all_dots"); + } + [ConCommand(commandName = "dtscanner", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.MACRO_SCANNER_HELP)] public static void CCScanner(ConCommandArgs args) { diff --git a/Code/Lang.cs b/Code/Lang.cs index 86a0d14..c39bcbb 100644 --- a/Code/Lang.cs +++ b/Code/Lang.cs @@ -143,6 +143,8 @@ public const string MACRO_DTZOOM_HELP = "Gives you 20 hooves and 200 feathers for getting around quickly.", MACRO_DTDAMAGE_HELP = "Gives you a lot of BoostDamage hidden item.", MACRO_SCANNER_HELP = "Gives you 100 boostEquipmentRecharge and the Radar Scanner equipment to easily search stages.", + MACRO_DTCLEANSE_HELP = "Removes all your buffs, timed buffs & dots.", + MACRO_LATEGAME_HELP = "Sets the current run to the 'lategame' as defined by HG. This command is DESTRUCTIVE.", MACRO_MIDGAME_HELP = "Sets the current run to the 'midgame' as defined by HG. This command is DESTRUCTIVE.", NEXTBOSS_HELP = "Sets the next teleporter/simulacrum boss to the specified boss. " + NEXTBOSS_ARGS, From 262dcb1f1ba6d54022a2b54006f3b9758f475d75 Mon Sep 17 00:00:00 2001 From: Wolfo Date: Wed, 31 Dec 2025 21:42:45 +0100 Subject: [PATCH 10/25] Update Buffs.cs --- Code/DT-Commands/Buffs.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/DT-Commands/Buffs.cs b/Code/DT-Commands/Buffs.cs index 1e9cf12..32e191c 100644 --- a/Code/DT-Commands/Buffs.cs +++ b/Code/DT-Commands/Buffs.cs @@ -105,7 +105,7 @@ private static void CCGiveBuff(ConCommandArgs args) { duration = 0; Log.MessageNetworked(String.Format(Lang.NEGATIVE_ARG, "duration"), args, LogLevel.MessageClientOnly); - //return; + return; } var target = ParseTarget(args, 3); From 1334a3761223b4a7caddc8dfec70100029f13eff Mon Sep 17 00:00:00 2001 From: Wolfo Date: Thu, 1 Jan 2026 08:49:52 +0100 Subject: [PATCH 11/25] Cleanup 2.0 --- CHANGELOG.md | 20 ++++----- Code/AutoCompletion/AutoCompleteManager.cs | 1 + Code/DT-Commands/Buffs.cs | 4 -- Code/DT-Commands/CurrentRun.cs | 50 +++++++++++----------- Code/DT-Commands/Items.cs | 13 +++--- Code/DT-Commands/LobbyManagement.cs | 4 +- Code/DT-Commands/Miscellaneous.cs | 2 - Code/DT-Commands/PlayerCommands.cs | 21 ++++----- Code/DT-Commands/Spawners.cs | 3 ++ Code/Hooks.cs | 13 +----- Code/Lang.cs | 11 +++-- Code/StringFinder.cs | 12 ------ 12 files changed, 62 insertions(+), 92 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 609589a..e17e66d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,18 +25,18 @@ * Added macro/short commands: - * 'dtscanner' -> 100 BoostEquipmentRechrage & Radar Scanner equip for easy map searching. - * 'dtdamage' -> x1000000 damage macro. - * 'dtpeace' -> 'kill_all' monsters & voids and 'no_enemies true' + * 'dtscanner': 100 BoostEquipmentRechrage & Radar Scanner equip for easy map searching. + * 'dtdamage': x1000000 damage macro. + * 'dtpeace': 'kill_all Monster & Void', 'no_enemies true', 'god true' + * 'dtcleanse': 'remove_all_buffs 0 & 1' & 'remove_all_dots' * 'random_equip' macro for 'give_equip random' * 'rich', -> Set money to 2 billion. * 'poor' -> Set money to 0. - * 'hud': shorthand toggle for 'hud_enable' * 'skill': shorthand for 'loadout_set_skill_variant self' * 'skin': shorthand for 'loadout_set_skin_variant self' - * 'unlimited_junk': Toggle for 'junk_unlimited' - * 'cleanse': Alt for 'remove_all_buffs 0 & 1' - + * 'toggle_hud': toggle 'hud_enable' convar + * 'unlimited_junk': Toggle for 'junk_unlimited' and give 12 junk + * Updated command functionality: * Item commands can now grant/remove channeled items * Item commands now mention you can type 0/1/2 instead of the name type. @@ -44,10 +44,10 @@ * 'spawn_interactable' now accepts amount. * 'create_pickup' now supports dropping drones & pickups. * 'create_pickup' switched {search} and {permanent/temp} argument spots. - * 'give_equip -1' now removes your equipment. - * 'give_buff' & 'remove_buff' now accept negative amounts to remove/give. + * 'give_equip' now accepts '-1|none' to remove your equipment. + * 'give .. remove_buff' now accept negative amounts to remove/give, like item commands. * 'loadout_set_skill_variant' now accepts 'self' - * 'random_items' changed default value to not give Lunars & Voids. + * 'random_items' changed default value to just give Tier1,2,3 * 'hurt' third optional argument to bypass armor&damage calculations. * 'kill_all' no value given now kills Monster & Void teams. * 'true_kill' now bypasses godmode and accepts 'pinged' & 'all' as target diff --git a/Code/AutoCompletion/AutoCompleteManager.cs b/Code/AutoCompletion/AutoCompleteManager.cs index 389f43c..a0c4201 100644 --- a/Code/AutoCompletion/AutoCompleteManager.cs +++ b/Code/AutoCompletion/AutoCompleteManager.cs @@ -72,6 +72,7 @@ internal static void RegisterAutoCompleteCommands() parser.RegisterStaticVariable("1", "1"); parser.RegisterStaticVariable("count", "count"); parser.RegisterStaticVariable("droneTier", "droneTier"); + parser.RegisterStaticVariable("duration", "duration"); parser.RegisterStaticVariable("ai", MasterCatalog.allAiMasters.Select(i => $"{(int)i.masterIndex}|{i.name}|{StringFinder.GetLangInvar(StringFinder.GetMasterName(i))}"), 1); parser.RegisterStaticVariable("artifact", ArtifactCatalog.artifactDefs.Select(i => $"{(int)i.artifactIndex}|{i.cachedName}|{StringFinder.GetLangInvar(i.nameToken)}"), 1); parser.RegisterStaticVariable("body", BodyCatalog.allBodyPrefabBodyBodyComponents.Select(i => $"{(int)i.bodyIndex}|{i.name}|{StringFinder.GetLangInvar(i.baseNameToken)}"), 1); diff --git a/Code/DT-Commands/Buffs.cs b/Code/DT-Commands/Buffs.cs index 32e191c..a3e56bf 100644 --- a/Code/DT-Commands/Buffs.cs +++ b/Code/DT-Commands/Buffs.cs @@ -103,7 +103,6 @@ private static void CCGiveBuff(ConCommandArgs args) } if (duration < 0f) { - duration = 0; Log.MessageNetworked(String.Format(Lang.NEGATIVE_ARG, "duration"), args, LogLevel.MessageClientOnly); return; } @@ -296,9 +295,6 @@ private static void CCRemoveBuffStacks(ConCommandArgs args) } } - - - [ConCommand(commandName = "remove_all_buffs", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.REMOVEALLBUFFS_HELP)] [AutoComplete(Lang.REMOVEALLBUFFS_ARGS)] private static void CCRemoveAllBuffs(ConCommandArgs args) diff --git a/Code/DT-Commands/CurrentRun.cs b/Code/DT-Commands/CurrentRun.cs index 8f58db6..44e222d 100644 --- a/Code/DT-Commands/CurrentRun.cs +++ b/Code/DT-Commands/CurrentRun.cs @@ -220,6 +220,7 @@ private static void CCLockExperience(ConCommandArgs args) Log.MessageNetworked(String.Format(lockExp ? Lang.SETTING_ENABLED : Lang.SETTING_DISABLED, "lock_exp"), args); } + [ConCommand(commandName = "kill_all", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.KILLALL_HELP)] [AutoComplete(Lang.KILLALL_ARGS)] private static void CCKillAll(ConCommandArgs args) @@ -229,40 +230,37 @@ private static void CCKillAll(ConCommandArgs args) Log.MessageNetworked(Lang.NOTINARUN_ERROR, args, LogLevel.MessageClientOnly); return; } - - if (args.Count > 0 && args[0] != Lang.DEFAULT_VALUE) + if (args.Count == 0 || args[0] == Lang.DEFAULT_VALUE) { - TeamIndex team = TeamIndex.Monster; - team = StringFinder.Instance.GetTeamFromPartial(args[0]); - if (team == StringFinder.TeamIndex_NotFound) - { - Log.MessageNetworked(Lang.TEAM_NOTFOUND, args, LogLevel.MessageClientOnly); - return; - } + DebugToolkit.InvokeCMD(args.sender, "kill_all", ((int)TeamIndex.Monster).ToString()); + DebugToolkit.InvokeCMD(args.sender, "kill_all", ((int)TeamIndex.Void).ToString()); + return; + } + + TeamIndex team = TeamIndex.Monster; + team = StringFinder.Instance.GetTeamFromPartial(args[0]); + if (team == StringFinder.TeamIndex_NotFound) + { + Log.MessageNetworked(Lang.TEAM_NOTFOUND, args, LogLevel.MessageClientOnly); + return; + } - int count = 0; - foreach (var teamComponent in TeamComponent.GetTeamMembers(team).ToList()) + int count = 0; + foreach (var teamComponent in TeamComponent.GetTeamMembers(team).ToList()) + { + var healthComponent = teamComponent.GetComponent(); + if (healthComponent) { - var healthComponent = teamComponent.GetComponent(); - if (healthComponent) + healthComponent.Suicide(null); + if (!healthComponent.alive) { - - healthComponent.Suicide(null); - if (!healthComponent.alive) - { - count++; - } + count++; } } - Log.MessageNetworked($"Killed {count} of team {team}.", args); - } - else - { - DebugToolkit.InvokeCMD(args.sender, "kill_all", ((int)TeamIndex.Monster).ToString()); - DebugToolkit.InvokeCMD(args.sender, "kill_all", ((int)TeamIndex.Void).ToString()); } + Log.MessageNetworked($"Killed {count} of team {team}.", args); } - + [ConCommand(commandName = "time_scale", flags = ConVarFlags.Engine | ConVarFlags.ExecuteOnServer, helpText = Lang.TIMESCALE_HELP)] [AutoComplete(Lang.TIMESCALE_ARGS)] private static void CCTimeScale(ConCommandArgs args) diff --git a/Code/DT-Commands/Items.cs b/Code/DT-Commands/Items.cs index 1f23f92..938734f 100644 --- a/Code/DT-Commands/Items.cs +++ b/Code/DT-Commands/Items.cs @@ -223,7 +223,7 @@ public static string getItemTypeName(ItemType type) [ConCommand(commandName = "random_items", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.RANDOMITEM_HELP)] [AutoComplete(Lang.RANDOMITEM_ARGS)] - private static void CCRandomItemsTiered(ConCommandArgs args) + private static void CCRandomItems(ConCommandArgs args) { if (!Run.instance) { @@ -319,7 +319,7 @@ private static void CCGiveEquipment(ConCommandArgs args) inventory.GiveRandomEquipment(); equip = inventory.GetEquipmentIndex(); } - else if (args[0] == "-1") + else if (args[0] == "-1" || args[0].ToUpperInvariant() == Lang.NONE) { inventory.SetEquipmentIndex(EquipmentIndex.None, true); Log.MessageNetworked(string.Format(Lang.REMOVEDEQUIP, target.name), args); @@ -478,15 +478,15 @@ private static void CCCreatePickup(ConCommandArgs args) string foundResults = string.Empty; if (def1) { - foundResults += $"{item}|{def1.name}|{Language.GetString(def1.nameToken)}"; + foundResults += $"{item}|{def1.name}|{Language.GetString(def1.nameToken)}\n"; } if (def2) { - foundResults += $"{equipment}|{def2.name}|{Language.GetString(def2.nameToken)}"; + foundResults += $"{equipment}|{def2.name}|{Language.GetString(def2.nameToken)}\n"; } if (def3) { - foundResults += $"{drone}|{def3.name}|{Language.GetString(def3.nameToken)}"; + foundResults += $"{drone}|{def3.name}|{Language.GetString(def3.nameToken)}\n"; } Log.MessageNetworked(string.Format(Lang.CREATEPICKUP_AMBIGIOUS, foundResults), args, LogLevel.MessageClientOnly); return; @@ -518,7 +518,6 @@ private static void CCCreatePickup(ConCommandArgs args) { pickupIndex = final, decayValue = type == PickupType.Temp ? 1f : 0f, - //upgradeValue }, }, body.transform.position, body.inputBank.aimDirection * 30f); } @@ -775,6 +774,7 @@ internal enum PickupCategory Pickup, Count, } + private static int GetItemCount(Inventory inventory, ItemIndex itemIndex, ItemType type) { switch (type) @@ -970,7 +970,6 @@ private static BasicPickupDropTable ParseDroptable(ConCommandArgs args, int inde droptable.Add(availableDropLists[ItemTier.Tier1], 100f); droptable.Add(availableDropLists[ItemTier.Tier2], 60f); droptable.Add(availableDropLists[ItemTier.Tier3], 4f); - droptable.Add(availableDropLists[ItemTier.Boss], 4f); } else if (args[index].ToUpperInvariant() == Lang.ALL) { diff --git a/Code/DT-Commands/LobbyManagement.cs b/Code/DT-Commands/LobbyManagement.cs index 43246f2..6817e32 100644 --- a/Code/DT-Commands/LobbyManagement.cs +++ b/Code/DT-Commands/LobbyManagement.cs @@ -1,7 +1,6 @@ using DebugToolkit.Permissions; using RoR2; using RoR2.Networking; -using System; using UnityEngine; using UnityEngine.Networking; using static DebugToolkit.Log; @@ -55,8 +54,7 @@ private static void CCTrueKill(ConCommandArgs args) { Log.Message(Lang.INSUFFICIENT_ARGS + Lang.PLAYER_OR_PINGED, LogLevel.Error); return; - } - + } CharacterMaster master = args.sender.master; if (args.Count > 0) { diff --git a/Code/DT-Commands/Miscellaneous.cs b/Code/DT-Commands/Miscellaneous.cs index 89e2f6e..f2f9d07 100644 --- a/Code/DT-Commands/Miscellaneous.cs +++ b/Code/DT-Commands/Miscellaneous.cs @@ -1,10 +1,8 @@ using BepInEx.Bootstrap; using RoR2; using System.Collections; -using System.Linq; using System.Text; using UnityEngine; -using UnityEngine.UIElements; namespace DebugToolkit.Commands { diff --git a/Code/DT-Commands/PlayerCommands.cs b/Code/DT-Commands/PlayerCommands.cs index 7deb917..c335b2f 100644 --- a/Code/DT-Commands/PlayerCommands.cs +++ b/Code/DT-Commands/PlayerCommands.cs @@ -282,7 +282,7 @@ private static void CCGoto_Boss(ConCommandArgs args) } - + [ConCommand(commandName = "spawn_as", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.SPAWNAS_HELP)] [AutoComplete(Lang.SPAWNAS_ARGS)] private static void CCSpawnAs(ConCommandArgs args) @@ -292,7 +292,7 @@ private static void CCSpawnAs(ConCommandArgs args) Log.MessageNetworked(Lang.NOTINARUN_ERROR, args, LogLevel.MessageClientOnly); return; } - if (args.Count == 0 || (args.sender == null && (args.Count < 3 || args[2] == Lang.DEFAULT_VALUE))) + if (args.Count == 0 || (args.sender == null && (args.Count < 2 || args[1] == Lang.DEFAULT_VALUE))) { Log.MessageNetworked(Lang.INSUFFICIENT_ARGS + Lang.SPAWNAS_ARGS, args, LogLevel.MessageClientOnly); return; @@ -307,7 +307,7 @@ private static void CCSpawnAs(ConCommandArgs args) GameObject newBody = BodyCatalog.GetBodyPrefab(bodyIndex); CharacterMaster master = args.senderMaster; - if (args.Count > 2 && args[2] != Lang.DEFAULT_VALUE) + if (args.Count > 1 && args[1] != Lang.DEFAULT_VALUE) { NetworkUser player = Util.GetNetUserFromString(args.userArgs, 1); if (player == null) @@ -324,10 +324,10 @@ private static void CCSpawnAs(ConCommandArgs args) Log.MessageNetworked(string.Format(Lang.EXPANSION_LOCKED, "body", Util.GetExpansion(expansion.requiredExpansion)), args, LogLevel.MessageClientOnly); return; } - - master.bodyPrefab = newBody; + master.originalBodyPrefab = newBody; - Log.MessageNetworked(args.sender.userName + " is spawning as " + newBody.name + " for the rest of the run.", args); + master.bodyPrefab = newBody; + Log.MessageNetworked(args.sender.userName + " is spawning as " + newBody.name, args); if (!master.GetBody()) { @@ -426,11 +426,14 @@ private static void CCHurt(ConCommandArgs args) Log.MessageNetworked("Nothing happened.", args, LogLevel.MessageClientOnly); return; } + + + target.body.healthComponent.TakeDamage(new DamageInfo() { damage = amount, position = target.body.corePosition, - damageType = bypassCalc ? DamageTypeExtended.BypassDamageCalculations : DamageTypeExtended.Generic + damageType = !bypassCalc ? DamageTypeCombo.Generic : new DamageTypeCombo(DamageType.BypassArmor & DamageType.BypassBlock & DamageType.BypassOneShotProtection, DamageTypeExtended.BypassDamageCalculations, DamageSource.NoneSpecified) }); Log.MessageNetworked($"Damaged {target.name} for {amount} hp.", args); } @@ -691,7 +694,6 @@ private static void GatherObjectState(System.Text.StringBuilder sb, Component co } } - //Apply_Skin is probably better, but does not save loadout [ConCommand(commandName = "loadout_set_skin_variant", flags = ConVarFlags.None, helpText = Lang.LOADOUTSKIN_HELP)] [AutoComplete(Lang.LOADOUTSKIN_ARGS)] public static void CCLoadoutSetSkinVariant(ConCommandArgs args) @@ -894,8 +896,7 @@ public static void CCResetSetStats(ConCommandArgs args) CCSetStats(args); } - //Idk how these work with client to server - //I think they just, don't. + //I don't know how these work with client to server, I think they just, don't. [ConCommand(commandName = "set_damage", flags = ConVarFlags.SenderMustBeServer, helpText = Lang.SETSTAT_HELP)] [ConCommand(commandName = "set_attackspeed", flags = ConVarFlags.SenderMustBeServer, helpText = Lang.SETSTAT_HELP)] [ConCommand(commandName = "set_crit", flags = ConVarFlags.SenderMustBeServer, helpText = Lang.SETSTAT_HELP)] diff --git a/Code/DT-Commands/Spawners.cs b/Code/DT-Commands/Spawners.cs index 250b981..74ff8e8 100644 --- a/Code/DT-Commands/Spawners.cs +++ b/Code/DT-Commands/Spawners.cs @@ -14,6 +14,7 @@ namespace DebugToolkit.Commands class Spawners { private static readonly Dictionary portals = new Dictionary(); + [ConCommand(commandName = "spawn_interactable", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.SPAWNINTERACTABLE_HELP)] [ConCommand(commandName = "spawn_interactible", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.SPAWNINTERACTABLE_HELP)] [AutoComplete(Lang.SPAWNINTERACTABLE_ARGS)] @@ -86,6 +87,7 @@ private static void CCSpawnInteractable(ConCommandArgs args) var direction = args.senderBody.inputBank.aimDirection; position = position + (args.senderBody.radius + distance) * new Vector3(direction.x, 0f, direction.z); } + Log.MessageNetworked(string.Format(Lang.SPAWN_ATTEMPT_2, amount, isc.prefab.name), args); int failed = 0; for (int i = 0; i < amount; i++) { @@ -206,6 +208,7 @@ private static void CCSpawnAI(ConCommandArgs args) Log.MessageNetworked(String.Format(Lang.PARSE_ERROR, "count", "int"), args, LogLevel.MessageClientOnly); return; } + EliteDef eliteDef = null; if (args.Count > 2 && args[2] != Lang.DEFAULT_VALUE) { diff --git a/Code/Hooks.cs b/Code/Hooks.cs index 814bc46..c164902 100644 --- a/Code/Hooks.cs +++ b/Code/Hooks.cs @@ -14,7 +14,6 @@ using UnityEngine; using UnityEngine.Networking; using Console = RoR2.Console; - namespace DebugToolkit { public sealed class Hooks @@ -95,7 +94,6 @@ public static void InitializeHooks() Run.onRunDestroyGlobal += Command_Noclip.DisableOnRunDestroy; //Buddha Mode hook - //On.RoR2.HealthComponent.TakeDamage += NonLethalDamage; On.RoR2.CharacterBody.Start += SetBuddhaMode; On.RoR2.CharacterMaster.Awake += SetGodMode; @@ -226,16 +224,7 @@ private static void SetGodMode(On.RoR2.CharacterMaster.orig_Awake orig, Characte self.godMode |= self.teamIndex == TeamIndex.Monster && godMonsters; } } - - private static void NonLethalDamage(On.RoR2.HealthComponent.orig_TakeDamage orig, HealthComponent self, DamageInfo damageInfo) - { - if (buddha && self.body.isPlayerControlled) - { - damageInfo.damageType |= DamageType.NonLethal; - } - orig(self, damageInfo); - } - + private static void InfiniteTowerRun_BeginNextWave(ILContext il) { var c = new ILCursor(il); diff --git a/Code/Lang.cs b/Code/Lang.cs index c39bcbb..0101f94 100644 --- a/Code/Lang.cs +++ b/Code/Lang.cs @@ -77,7 +77,6 @@ public const string BIND_HELP = "Bind a key to execute specific commands. " + BIND_ARGS, BIND_DELETE_HELP = "Remove a custom bind from the macro system of DebugToolkit. " + BIND_DELETE_ARGS, BIND_RELOAD_HELP = "Reload the macro system of DebugToolkit. " + NO_ARGS, - //BUDDHA_HELP = "Become immortal. Instead of refusing damage you just refuse to take lethal damage.\nIt works by giving all damage a player takes DamageType.NonLethal. " + ENABLE_ARGS, BUDDHA_HELP = "Players become immortal, but remain attackable. " + ENABLE_ARGS, BUDDHAENEMY_HELP = "Enemies become immortal, but remain attackable. " + ENABLE_ARGS, CHANGETEAM_HELP = "Change the specified player to the specified team. " + CHANGETEAM_ARGS, @@ -101,9 +100,6 @@ public const string GIVEEQUIP_HELP = "Gives the specified equipment to a target. " + GIVEEQUIP_ARGS, RANDOMEQUIP_HELP = "Gives a random equipment to a target. " + RANDOMEQUIP_ARGS, GIVEITEM_HELP = "Gives the specified item to a target. " + GIVEITEM_ARGS, - GIVEDRONE_HELP = "Summons the specified drone to a target. " + GIVEDRONE_ARGS, - REMOVEALLDRONES_HELP = "Removes all drones from the target. " + REMOVEALLDRONES_ARGS, - KILL_ALL_MINIONS_HELP = "Kills all minions owned by target. " + REMOVEALLDRONES_ARGS, GIVELUNAR_HELP = "Gives amount of lunar coin to you. " + GIVELUNAR_ARGS, GIVEVOID_HELP = "Gives amount of void markers to you. " + GIVELUNAR_ARGS, GIVEMONEY_HELP = "Gives the specified amount of money to the specified player. " + GIVEMONEY_ARGS, @@ -113,7 +109,10 @@ public const string GODENEMY_HELP = "All monster team members become invincible. " + ENABLE_ARGS, SETSTAT_HELP = "Sets the base stat to a specific value for yourself or target, and the level stat to 0. " + SETSTATS_ARGS, RESETSTAT_HELP = "Resets the base & level stats for yourself or target", - + GIVEDRONE_HELP = "Summons the specified drone to a target. " + GIVEDRONE_ARGS, + REMOVEALLDRONES_HELP = "Removes all drones from the target. " + REMOVEALLDRONES_ARGS, + KILL_ALL_MINIONS_HELP = "Kills all minions owned by target. " + REMOVEALLDRONES_ARGS, + HEAL_HELP = "Heal yourself or another target. " + HEAL_ARGS, HURT_HELP = "Deal generic damage to yourself or another target. " + HURT_ARGS, KICK_HELP = "Kicks the specified player from the session. " + PLAYER_ARGS, @@ -159,7 +158,6 @@ public const string POSTSOUNDEVENT_HELP = "Post a sound event to the AkSoundEngine (WWise) either by its event name or event ID. " + POSTSOUNDEVENT_ARGS, PREVENT_PROFILE_WRITING_HELP = "Prevent saving the user profile to avoid bogus data. " + ENABLE_ARGS, RANDOMITEM_HELP = "Generate random items from the available item tiers. " + RANDOMITEM_ARGS, - RANDOMITEM_HELP2 = "Grant randoms of normal tiers with option for Lunar/Voids. " + RANDOMITEM_ARGS, RELOADCONFIG_HELP = "Reload all default config files from all loaded plugins.", REMOVEALLBUFFS_HELP = "Removes all buffs from a character. " + REMOVEALLBUFFS_ARGS, REMOVEALLDOTS_HELP = "Removes all DoTs from a character. " + REMOVEALLDOTS_ARGS, @@ -261,6 +259,7 @@ public const string ITEM = "ITEM", PINGED = "PINGED", RANDOM = "RANDOM", + NONE = "NONE", SIMULACRUM = "SIMULACRUM", VOIDFIELDS = "VOIDFIELDS" ; diff --git a/Code/StringFinder.cs b/Code/StringFinder.cs index 72ba03d..a88dbe1 100644 --- a/Code/StringFinder.cs +++ b/Code/StringFinder.cs @@ -39,18 +39,6 @@ private StringFinder() private static void GatherCSCs() { - /*GatherAddressableAssets("/csc", (asset) => - { - characterSpawnCard.Add(new DirectorCard - { - spawnCard = asset, - forbiddenUnlockableDef = null, - minimumStageCompletions = 0, - preventOverhead = true, - spawnDistance = DirectorCore.MonsterSpawnDistance.Standard, - }); - });*/ - RoR2Application.onLoad += () => { //I imagine this would fail to get modded MultiCSC From 43325499277f0a7a832e581b7a2d24c8cf12fcbb Mon Sep 17 00:00:00 2001 From: Wolfo Date: Thu, 1 Jan 2026 08:54:48 +0100 Subject: [PATCH 12/25] empty spaces / unused diffs again --- Code/AutoCompletion/AutoCompleteManager.cs | 4 ++-- Code/DT-Commands/CurrentRun.cs | 2 +- Code/DT-Commands/PlayerCommands.cs | 5 +---- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Code/AutoCompletion/AutoCompleteManager.cs b/Code/AutoCompletion/AutoCompleteManager.cs index a0c4201..e5005f0 100644 --- a/Code/AutoCompletion/AutoCompleteManager.cs +++ b/Code/AutoCompletion/AutoCompleteManager.cs @@ -1,8 +1,8 @@ -using DebugToolkit.Commands; -using RoR2; +using RoR2; using System; using System.Collections.Generic; using System.Linq; +using DebugToolkit.Commands; namespace DebugToolkit { diff --git a/Code/DT-Commands/CurrentRun.cs b/Code/DT-Commands/CurrentRun.cs index 44e222d..daf33fb 100644 --- a/Code/DT-Commands/CurrentRun.cs +++ b/Code/DT-Commands/CurrentRun.cs @@ -260,7 +260,7 @@ private static void CCKillAll(ConCommandArgs args) } Log.MessageNetworked($"Killed {count} of team {team}.", args); } - + [ConCommand(commandName = "time_scale", flags = ConVarFlags.Engine | ConVarFlags.ExecuteOnServer, helpText = Lang.TIMESCALE_HELP)] [AutoComplete(Lang.TIMESCALE_ARGS)] private static void CCTimeScale(ConCommandArgs args) diff --git a/Code/DT-Commands/PlayerCommands.cs b/Code/DT-Commands/PlayerCommands.cs index c335b2f..9061ba3 100644 --- a/Code/DT-Commands/PlayerCommands.cs +++ b/Code/DT-Commands/PlayerCommands.cs @@ -426,9 +426,6 @@ private static void CCHurt(ConCommandArgs args) Log.MessageNetworked("Nothing happened.", args, LogLevel.MessageClientOnly); return; } - - - target.body.healthComponent.TakeDamage(new DamageInfo() { damage = amount, @@ -693,7 +690,7 @@ private static void GatherObjectState(System.Text.StringBuilder sb, Component co sb.AppendLine($"{esm.customName} state: {esm.state?.ToString() ?? string.Empty}"); } } - + [ConCommand(commandName = "loadout_set_skin_variant", flags = ConVarFlags.None, helpText = Lang.LOADOUTSKIN_HELP)] [AutoComplete(Lang.LOADOUTSKIN_ARGS)] public static void CCLoadoutSetSkinVariant(ConCommandArgs args) From 21945d5d7b1ca6842ac1cc587838943f7b30026d Mon Sep 17 00:00:00 2001 From: Wolfo Date: Sat, 3 Jan 2026 12:05:33 +0100 Subject: [PATCH 13/25] Fixed toggle_time not really working as it should if time_scale was already set --- Code/DT-Commands/CurrentRun.cs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/Code/DT-Commands/CurrentRun.cs b/Code/DT-Commands/CurrentRun.cs index daf33fb..9a0e551 100644 --- a/Code/DT-Commands/CurrentRun.cs +++ b/Code/DT-Commands/CurrentRun.cs @@ -284,10 +284,17 @@ private static void CCTimeScale(ConCommandArgs args) [ConCommand(commandName = "toggle_time", flags = ConVarFlags.None, helpText = Lang.TOGGLETIME_HELP)] private static void CCTogglePause(ConCommandArgs args) { - float newTimeScale = prevTimeScale; - prevTimeScale = Time.timeScale; - Time.timeScale = newTimeScale; - TimescaleNet.Invoke(newTimeScale); + float newTime = 0; + if (Time.timeScale == 0) + { + newTime = prevTimeScale == 0 ? 1 : prevTimeScale; + } + else + { + prevTimeScale = Time.timeScale; + } + Time.timeScale = newTime; + TimescaleNet.Invoke(newTime); } [ConCommand(commandName = "stop_timer", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.STOPTIMER_HELP)] From 6d824ec1795adbca7482c366a41c4b2aa423fe32 Mon Sep 17 00:00:00 2001 From: Wolfo Date: Sun, 4 Jan 2026 12:39:21 +0100 Subject: [PATCH 14/25] Missed a type --- Code/Lang.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Lang.cs b/Code/Lang.cs index 0101f94..2bfd6aa 100644 --- a/Code/Lang.cs +++ b/Code/Lang.cs @@ -47,7 +47,7 @@ public const string NO_ARGS = "Requires 0 arguments.", PERM_MOD_ARGS = "Requires 2 arguments: {permission_level} {player}", POSTSOUNDEVENT_ARGS = "Requires 1 argument: {sound_event (event_name|event_id)}", - RANDOMITEM_ARGS = "Requires 1 (3 if from server) argument: {count} [droptable (droptable|'all'):'\"Tier1:100,Tier2:60,Tier3:4\"'] [itemTypes:'permanent'] [target (player|'pinged'|'evolution'|'simulacrum'|'voidfields'|'devotion'):]", + RANDOMITEM_ARGS = "Requires 1 (3 if from server) argument: {count} [droptable (droptable|'all'):'\"Tier1:100,Tier2:60,Tier3:4\"'] [item_type:'permanent'] [target (player|'pinged'|'evolution'|'simulacrum'|'voidfields'|'devotion'):]", REMOVEALLBUFFS_ARGS = "Requires 0 (2 if from server) arguments: [timed (0|1):0/false] [target (player|'pinged'):]", REMOVEALLDOTS_ARGS = "Requires 0 (1 if from server) arguments: [target (player|'pinged'):]", REMOVEALLITEMS_ARGS = "Requires 0 (1 if from server) arguments: [target (player|'pinged'|'evolution'|'simulacrum'|'voidfields'|'devotion'):]", From dd6328b899d679d17087f40901114932a22a4bab Mon Sep 17 00:00:00 2001 From: Wolfo Date: Fri, 9 Jan 2026 10:53:31 +0100 Subject: [PATCH 15/25] set_difficulty command This should help if testing smth like how does it work on eclipse vs other difficulty. Does mean the mod needs to depend on R2API_Difficulty. -For modded difficulties -For DifficultyDef to DifficutlyIndex (not invanilla I think) --- Code/AutoCompletion/AutoCompleteManager.cs | 1 + Code/DT-Commands/CurrentRun.cs | 50 ++++++++++++++++++++++ Code/DT-Commands/Lists.cs | 18 ++++++++ Code/Lang.cs | 3 ++ Code/StringFinder.cs | 48 +++++++++++++++++++-- DebugToolkit.csproj | 1 + Thunderstore/thunderstore.toml | 1 + 7 files changed, 118 insertions(+), 4 deletions(-) diff --git a/Code/AutoCompletion/AutoCompleteManager.cs b/Code/AutoCompletion/AutoCompleteManager.cs index e5005f0..1a30ba7 100644 --- a/Code/AutoCompletion/AutoCompleteManager.cs +++ b/Code/AutoCompletion/AutoCompleteManager.cs @@ -75,6 +75,7 @@ internal static void RegisterAutoCompleteCommands() parser.RegisterStaticVariable("duration", "duration"); parser.RegisterStaticVariable("ai", MasterCatalog.allAiMasters.Select(i => $"{(int)i.masterIndex}|{i.name}|{StringFinder.GetLangInvar(StringFinder.GetMasterName(i))}"), 1); parser.RegisterStaticVariable("artifact", ArtifactCatalog.artifactDefs.Select(i => $"{(int)i.artifactIndex}|{i.cachedName}|{StringFinder.GetLangInvar(i.nameToken)}"), 1); + parser.RegisterStaticVariable("difficulty", R2API.DifficultyAPI.difficultyDefinitions.Select(i => $"{(int)i.Key}|{StringFinder.GetLangInvar(i.Value.nameToken)}"), 1); parser.RegisterStaticVariable("body", BodyCatalog.allBodyPrefabBodyBodyComponents.Select(i => $"{(int)i.bodyIndex}|{i.name}|{StringFinder.GetLangInvar(i.baseNameToken)}"), 1); parser.RegisterStaticVariable("buff", BuffCatalog.buffDefs.Select(i => $"{(int)i.buffIndex}|{StringFinder.GetLangInvar(i.name)}"), 1); parser.RegisterStaticVariable("droptable", ItemTierCatalog.allItemTierDefs.OrderBy(i => i.tier).Select(i => $"{(int)i.tier}|{i.name}"), 1); diff --git a/Code/DT-Commands/CurrentRun.cs b/Code/DT-Commands/CurrentRun.cs index 9a0e551..b806dc2 100644 --- a/Code/DT-Commands/CurrentRun.cs +++ b/Code/DT-Commands/CurrentRun.cs @@ -789,6 +789,56 @@ public static void CCEvolveLemurians(ConCommandArgs args) } } + + [ConCommand(commandName = "set_difficulty", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.SETDIFFICULTY_HELP)] + [AutoComplete(Lang.SETDIFFICULTY_ARGS)] + public static void CCSetDifficulty(ConCommandArgs args) + { + if (!Run.instance) + { + Log.MessageNetworked(Lang.NOTINARUN_ERROR, args, LogLevel.MessageClientOnly); + return; + } + if (args.Count < 1) + { + Log.MessageNetworked(Lang.INSUFFICIENT_ARGS + Lang.SETDIFFICULTY_ARGS, args, LogLevel.MessageClientOnly); + return; + } + + DifficultyIndex difficultyIndex = StringFinder.Instance.GetDifficultyFromPartial(args[0]); + DifficultyDef difficultyDef = DifficultyCatalog.GetDifficultyDef(difficultyIndex); + if (difficultyIndex == DifficultyIndex.Invalid || difficultyDef == null) + { + Log.MessageNetworked(string.Format(Lang.OBJECT_NOTFOUND, "difficulty", args[0]), args, LogLevel.MessageClientOnly); + return; + } + + Run.instance.selectedDifficulty = difficultyIndex; + Log.MessageNetworked("Setting the runs selected difficulty to: "+ Language.GetString(difficultyDef.nameToken), args); + + if (Run.instance.uiInstances.Count > 0) + { + //Refreshes HUD to match set difficulty + //Is there a way to do this on both client & server? + Run.instance.uiInstances[0].GetComponentInChildren()?.Start(); + } + foreach (var player in PlayerCharacterMasterController.instances) + { + //Ensure proper Helper items, maybe not most accurate for modded difficulties. + player.master.inventory.ResetItemPermanent(RoR2Content.Items.DrizzlePlayerHelper); + player.master.inventory.ResetItemPermanent(RoR2Content.Items.MonsoonPlayerHelper); + if (difficultyIndex == DifficultyIndex.Easy) + { + player.master.inventory.GiveItemPermanent(RoR2Content.Items.DrizzlePlayerHelper, 1); + } + else if (difficultyDef.countsAsHardMode) + { + player.master.inventory.GiveItemPermanent(RoR2Content.Items.MonsoonPlayerHelper, 1); + } + } + + } + } // ReSharper disable once ClassNeverInstantiated.Global diff --git a/Code/DT-Commands/Lists.cs b/Code/DT-Commands/Lists.cs index 4c32146..1a73125 100644 --- a/Code/DT-Commands/Lists.cs +++ b/Code/DT-Commands/Lists.cs @@ -1,5 +1,6 @@ using RoR2; using System.Collections.Generic; +using System.Linq; using System.Text; using UnityEngine.Networking; using static DebugToolkit.Log; @@ -71,6 +72,23 @@ private static void CCListArtifact(ConCommandArgs args) Log.MessageNetworked(s, args, LogLevel.MessageClientOnly); } + [ConCommand(commandName = "list_difficulty", flags = ConVarFlags.None, helpText = Lang.LISTDIFFICULTY_HELP)] + private static void CCListDifficulty(ConCommandArgs args) + { + StringBuilder sb = new StringBuilder(); + var arg = args.Count > 0 ? args[0] : ""; + var indices = StringFinder.Instance.GetDifficultiesFromPartial(arg); + foreach (var index in indices) + { + var difficultyDef = DifficultyCatalog.GetDifficultyDef(index); + var langInvar = StringFinder.GetLangInvar(difficultyDef.nameToken); + sb.AppendLine($"[{(int)index}]{difficultyDef.nameToken}={langInvar}"); + } + var s = sb.Length > 0 ? sb.ToString().TrimEnd('\n') : string.Format(Lang.NOMATCH_ERROR, "difficulty", arg); + Log.MessageNetworked(s, args, LogLevel.MessageClientOnly); + } + + [ConCommand(commandName = "list_ai", flags = ConVarFlags.None, helpText = Lang.LISTAI_HELP)] [AutoComplete(Lang.LISTQUERY_ARGS)] private static void CCListAI(ConCommandArgs args) diff --git a/Code/Lang.cs b/Code/Lang.cs index 2bfd6aa..585bde3 100644 --- a/Code/Lang.cs +++ b/Code/Lang.cs @@ -62,6 +62,7 @@ public const string RUNSETWAVESCLEARED_ARGS = "Requires 1 argument {wave}", SEED_ARGS = "Requires 0 or 1 argument: [new_seed]", SETARTIFACT_ARGS = "Requires 1 (2 if using 'all') argument: {artifact (artifact|'all')} [enable (0|1)]", + SETDIFFICULTY_ARGS = "Requires 1 argument: {difficulty}", SPAWNAI_ARGS = "Requires 1 argument: {ai} [count:1] [elite:None] [braindead (0|1):0/false] [team (team|'ally'):Monster]", SPAWNAS_ARGS = "Requires 1 (2 if from server) argument: {body} [player:]", SPAWNBODY_ARGS = "Requires 1 argument: {body}", @@ -119,6 +120,7 @@ public const string KILLALL_HELP = "Kill all entities on the specified team. " + KILLALL_ARGS, LISTAI_HELP = "List all Masters and their language invariants. " + LISTQUERY_ARGS, LISTARTIFACT_HELP = "List all Artifacts and their language invariants. " + LISTQUERY_ARGS, + LISTDIFFICULTY_HELP = "List all Difficulties and their language invariants. " + LISTQUERY_ARGS, LISTBODY_HELP = "List all Bodies and their language invariants. " + LISTQUERY_ARGS, LISTBUFF_HELP = "List all Buffs and whether they stack. " + LISTQUERY_ARGS, LISTDIRECTORCARDS_HELP = "List all Director Cards. " + LISTQUERY_ARGS, @@ -174,6 +176,7 @@ public const string RUNSETWAVESCLEARED_HELP = "Set the Simulacrum waves cleared. Must be positive. " + RUNSETWAVESCLEARED_ARGS, SEED_HELP = "Gets/Sets the game seed until game close. Use 0 to reset to vanilla generation. " + SEED_ARGS, SETARTIFACT_HELP = "Enable/disable an Artifact. " + SETARTIFACT_ARGS, + SETDIFFICULTY_HELP = "Sets the runs selected difficulty. " + SETDIFFICULTY_ARGS, SPAWNAS_HELP = "Respawn the specified player using the specified body prefab. " + SPAWNAS_ARGS, SPAWNAI_HELP = "Spawns the specified CharacterMaster. " + SPAWNAI_ARGS, SPAWNBODY_HELP = "Spawns the specified dummy body. " + SPAWNBODY_ARGS, diff --git a/Code/StringFinder.cs b/Code/StringFinder.cs index a88dbe1..20d0bfa 100644 --- a/Code/StringFinder.cs +++ b/Code/StringFinder.cs @@ -61,7 +61,7 @@ private static void GatherCSCs() } var filteredList = - CSCList.Where(spawnCard => spawnCard is CharacterSpawnCard && characterSpawnCard.All(existingCSC => existingCSC.spawnCard.name != spawnCard.name)); + CSCList.Where(spawnCard => spawnCard is CharacterSpawnCard && characterSpawnCard.All(existingCSC => existingCSC.spawnCard != spawnCard)); foreach (var card in filteredList) { characterSpawnCard.Add(new DirectorCard @@ -81,11 +81,11 @@ private void GatherISCs() { //Doing this first means only getting loaded spawn cards. //Which for vanilla isn't a lot of them (38) - //But itll find any modded ones and mod-edited ones. + //But itll find any modded ones and mod-loaded ones. var ISCList = Resources.FindObjectsOfTypeAll(typeof(InteractableSpawnCard)) as InteractableSpawnCard[]; //Unless there's some issue with WaitForFinished() - //Gotta do it this way to get vanillaInteractables first then moddedInteractables, without jumbling up the order + //Have do it this way to get vanillaInteractables first then moddedInteractables, without jumbling up the order foreach (var resourceLocator in Addressables.ResourceLocators) { foreach (var key in resourceLocator.Keys) @@ -99,7 +99,7 @@ private void GatherISCs() } var filteredList = - ISCList.Where(spawnCard => spawnCard is InteractableSpawnCard && interactableSpawnCards.All(existingIsc => existingIsc.name != spawnCard.name)); + ISCList.Where(spawnCard => spawnCard is InteractableSpawnCard && interactableSpawnCards.All(existingIsc => existingIsc != spawnCard)); interactableSpawnCards.AddRange(filteredList); }; } @@ -299,6 +299,46 @@ public DotController.DotIndex GetDotFromPartial(string name) } } + /// + /// Returns an DifficultyIndex when provided with an index or partial/invariant. + /// + /// Matches either the exact (int)Index or Partial Invariant + /// Returns the DifficultyIndex if a match is found, or returns DifficultyIndex.Invalid + public DifficultyIndex GetDifficultyFromPartial(string name) + { + return GetDifficultiesFromPartial(name).DefaultIfEmpty(DifficultyIndex.Invalid).First(); + } + + /// + /// Returns an iterator of DifficultyIndex's when provided with an index or partial/invariant. + /// + /// Matches either the exact (int)Index or Partial Invariant + /// Returns an iterator with all DifficultyIndex's matched + public IEnumerable GetDifficultiesFromPartial(string name) + { + //Vanilla has no DifficultyDef -> Index + //Modded difficulties are also not stored in DifficultyCatalog usually. + if (TextSerialization.TryParseInvariant(name, out int i)) + { + var index = (DifficultyIndex)i; + if (DifficultyCatalog.GetDifficultyDef(index) != null) + { + yield return index; + } + yield break; + } + name = name.ToUpperInvariant(); + foreach (var dict in R2API.DifficultyAPI.difficultyDefinitions) + { + var langInvar = GetLangInvar(dict.Value.nameToken).ToUpper(); + if (dict.Value.nameToken.ToUpper().Contains(name) || langInvar.Contains(name)) + { + yield return dict.Key; + } + } + } + + /// /// Returns an EquipmentIndex when provided with an index or partial/invariant. /// diff --git a/DebugToolkit.csproj b/DebugToolkit.csproj index 728884c..c1031d4 100644 --- a/DebugToolkit.csproj +++ b/DebugToolkit.csproj @@ -90,6 +90,7 @@ + diff --git a/Thunderstore/thunderstore.toml b/Thunderstore/thunderstore.toml index 4632137..ed3b98b 100644 --- a/Thunderstore/thunderstore.toml +++ b/Thunderstore/thunderstore.toml @@ -15,6 +15,7 @@ RiskofThunder-R2API_Core = "5.1.7" RiskofThunder-R2API_ContentManagement = "1.0.10" RiskofThunder-R2API_Networking = "1.0.3" RiskofThunder-R2API_Prefab = "1.1.1" +RiskofThunder-R2API_Difficulty = "1.1.2" [build] icon = "./icon.png" From 8372c1c897278a6c533081b01b4f12546aadaad8 Mon Sep 17 00:00:00 2001 From: Wolfo Date: Fri, 9 Jan 2026 13:45:38 +0100 Subject: [PATCH 16/25] Made the set_ stats 1 stat to not fill up help command. Do think this is still a good command to have. Fixed Parse.BuffTarget 'pinged' returning wrong fail message if it fails. --- Code/AutoCompletion/AutoCompleteManager.cs | 4 +- Code/DT-Commands/Buffs.cs | 2 +- Code/DT-Commands/PlayerCommands.cs | 158 +++++++-------------- Code/Lang.cs | 5 +- 4 files changed, 61 insertions(+), 108 deletions(-) diff --git a/Code/AutoCompletion/AutoCompleteManager.cs b/Code/AutoCompletion/AutoCompleteManager.cs index 1a30ba7..e1122bc 100644 --- a/Code/AutoCompletion/AutoCompleteManager.cs +++ b/Code/AutoCompletion/AutoCompleteManager.cs @@ -106,7 +106,9 @@ internal static void RegisterAutoCompleteCommands() parser.RegisterStaticVariable("item_type", CollectEnumNames(typeof(Items.ItemType), typeof(int)), 1); parser.RegisterStaticVariable("pickup_type", CollectEnumNames(typeof(Items.PickupType), typeof(int)), 1); parser.RegisterStaticVariable("pickup_category", CollectEnumNames(typeof(Items.PickupCategory), typeof(int)), 1); - + + parser.RegisterStaticVariable("stat", CollectEnumNames(typeof(PlayerCommands.Stat), typeof(int)), 1); + parser.Scan(System.Reflection.Assembly.GetExecutingAssembly()); } diff --git a/Code/DT-Commands/Buffs.cs b/Code/DT-Commands/Buffs.cs index a3e56bf..6ea36ec 100644 --- a/Code/DT-Commands/Buffs.cs +++ b/Code/DT-Commands/Buffs.cs @@ -617,7 +617,7 @@ internal static CommandTarget ParseTarget(ConCommandArgs args, int index) target = targetMaster?.GetBody(); } } - if (target == null) + if (target == null && failMessage != null) { failMessage = Lang.PLAYER_NOTFOUND; } diff --git a/Code/DT-Commands/PlayerCommands.cs b/Code/DT-Commands/PlayerCommands.cs index 9061ba3..65536b5 100644 --- a/Code/DT-Commands/PlayerCommands.cs +++ b/Code/DT-Commands/PlayerCommands.cs @@ -883,25 +883,8 @@ public static void CCToggleHUD(ConCommandArgs args) RoR2.UI.HUD.cvHudEnable.SetBool(!RoR2.UI.HUD.cvHudEnable.value); Log.MessageNetworked(String.Format(RoR2.UI.HUD.cvHudEnable.value ? Lang.SETTING_ENABLED : Lang.SETTING_DISABLED, "Hud"), args, LogLevel.MessageClientOnly); } - - - [ConCommand(commandName = "reset_stats", flags = ConVarFlags.SenderMustBeServer, helpText = Lang.RESETSTAT_HELP)] - [AutoComplete(Lang.PLAYER_OR_PINGED)] - public static void CCResetSetStats(ConCommandArgs args) - { - args.userArgs.Insert(0,""); - CCSetStats(args); - } - - //I don't know how these work with client to server, I think they just, don't. - [ConCommand(commandName = "set_damage", flags = ConVarFlags.SenderMustBeServer, helpText = Lang.SETSTAT_HELP)] - [ConCommand(commandName = "set_attackspeed", flags = ConVarFlags.SenderMustBeServer, helpText = Lang.SETSTAT_HELP)] - [ConCommand(commandName = "set_crit", flags = ConVarFlags.SenderMustBeServer, helpText = Lang.SETSTAT_HELP)] - [ConCommand(commandName = "set_health", flags = ConVarFlags.SenderMustBeServer, helpText = Lang.SETSTAT_HELP)] - [ConCommand(commandName = "set_regen", flags = ConVarFlags.SenderMustBeServer, helpText = Lang.SETSTAT_HELP)] - [ConCommand(commandName = "set_armor", flags = ConVarFlags.SenderMustBeServer, helpText = Lang.SETSTAT_HELP)] - [ConCommand(commandName = "set_movespeed", flags = ConVarFlags.SenderMustBeServer, helpText = Lang.SETSTAT_HELP)] - [ConCommand(commandName = "set_jumppower", flags = ConVarFlags.SenderMustBeServer, helpText = Lang.SETSTAT_HELP)] + + [ConCommand(commandName = "set_stat", flags = ConVarFlags.SenderMustBeServer, helpText = Lang.SETSTAT_HELP)] [AutoComplete(Lang.SETSTATS_ARGS)] public static void CCSetStats(ConCommandArgs args) { @@ -910,60 +893,43 @@ public static void CCSetStats(ConCommandArgs args) Log.MessageNetworked(Lang.NOTINARUN_ERROR, args, LogLevel.MessageClientOnly); return; } - if (args.Count == 0 || (args.sender == null && (args.Count < 2 || args[1] == Lang.DEFAULT_VALUE))) + + if (args.Count == 0 || (args.sender == null && (args.Count < 3 || args[2] == Lang.DEFAULT_VALUE))) { Log.MessageNetworked(Lang.INSUFFICIENT_ARGS + Lang.SETSTATS_ARGS, args, LogLevel.MessageClientOnly); return; } - var target = Buffs.ParseTarget(args, 1); + var target = Buffs.ParseTarget(args, 2); if (target.failMessage != null) { Log.MessageNetworked(target.failMessage, args, LogLevel.MessageClientOnly); return; } - if (!TextSerialization.TryParseInvariant(args[0], out float amount)) + bool reset = false; + float amount = 0; + if (args.Count == 1 || args[1] == Lang.DEFAULT_VALUE || args[1].ToUpperInvariant() == "RESET") { - Log.MessageNetworked(string.Format(Lang.PARSE_ERROR, "amount", "float"), args, LogLevel.MessageClientOnly); - return; + reset = true; } - - Stat statToSet = Stat.Reset; - string command = args.commandName; - - switch (command) + else { - case "set_damage": - statToSet = Stat.Damage; - break; - case "set_attackspeed": - statToSet = Stat.AttackSpeed; - break; - case "set_crit": - statToSet = Stat.Crit; - break; - case "set_health": - statToSet = Stat.MaxHealth; - break; - case "set_regen": - statToSet = Stat.Regen; - break; - case "set_armor": - statToSet = Stat.Armor; - break; - case "set_movespeed": - statToSet = Stat.MoveSpeed; - break; - case "set_jumppower": - statToSet = Stat.JumpPower; - break; - case "reset_stats": - statToSet = Stat.Reset; - break; + if (!TextSerialization.TryParseInvariant(args[1], out amount)) + { + Log.MessageNetworked(string.Format(Lang.PARSE_ERROR, "amount", "float"), args, LogLevel.MessageClientOnly); + return; + } + } + + Stat statToSet = Enum.TryParse(args[0], true, out Stat itemType) ? itemType : Stat.None; + if (statToSet == Stat.None) + { + Log.MessageNetworked(string.Format(Lang.PARSE_ERROR, "stat", "string"), args, LogLevel.MessageClientOnly); + return; } - SetStatsForBody(target.body, statToSet, amount); - if (statToSet == Stat.Reset) + SetStatsForBody(target.body, statToSet, amount, reset); + if (reset) { - Log.MessageNetworked($"Reset {target.name}'s stats to their base values.", args); + Log.MessageNetworked($"Reset {target.name}'s {statToSet} to it's base value.", args); } else { @@ -975,75 +941,61 @@ public static void CCSetStats(ConCommandArgs args) public enum Stat { + None = -1, Damage, AttackSpeed, Crit, - MaxHealth, + Health, + Shield, Regen, Armor, MoveSpeed, - JumpPower, - Reset, + Acceleration, + JumpPower, } - public static void SetStatsForBody(CharacterBody body, Stat stat, float amount) + public static void SetStatsForBody(CharacterBody body, Stat stat, float amount, bool reset) { var ogBody = body.master.bodyPrefab.GetComponent(); switch (stat) { - case Stat.Damage: - body.baseDamage = amount; - body.levelDamage = 0; + body.baseDamage = reset ? ogBody.baseDamage : amount; + body.levelDamage = reset ? ogBody.levelDamage : 0; break; case Stat.AttackSpeed: - body.baseAttackSpeed = amount; - body.levelAttackSpeed = 0; + body.baseAttackSpeed = reset ? ogBody.baseAttackSpeed : amount; + body.levelAttackSpeed = reset ? ogBody.levelAttackSpeed : 0; break; case Stat.Crit: - body.baseCrit = amount; - body.levelCrit = 0; + body.baseCrit = reset ? ogBody.baseCrit : amount; + body.levelCrit = reset ? ogBody.levelCrit : 0; + break; + case Stat.Health: + body.baseMaxHealth = reset ? ogBody.baseMaxHealth : amount; + body.levelMaxHealth = reset ? ogBody.levelMaxHealth : 0; break; - case Stat.MaxHealth: - body.baseMaxHealth = amount; - body.levelMaxHealth = 0; + case Stat.Shield: + body.baseMaxShield = reset ? ogBody.baseMaxShield : amount; + body.levelMaxShield = reset ? ogBody.levelMaxShield : 0; break; case Stat.Regen: - body.baseRegen = amount; - body.levelRegen = 0; + body.baseRegen = reset ? ogBody.baseRegen : amount; + body.levelRegen = reset ? ogBody.levelRegen : 0; break; case Stat.Armor: - body.baseArmor = amount; - body.levelArmor = 0; + body.baseArmor = reset ? ogBody.baseArmor : amount; + body.levelArmor = reset ? ogBody.levelArmor : 0; break; case Stat.MoveSpeed: - body.baseMoveSpeed = amount; - body.levelMoveSpeed = 0; - body.baseAcceleration = (ogBody.baseAcceleration * (amount / ogBody.baseMoveSpeed)); + body.baseMoveSpeed = reset ? ogBody.baseMoveSpeed : amount; + body.levelMoveSpeed = reset ? ogBody.levelMoveSpeed : 0; break; - case Stat.JumpPower: - body.baseJumpPower = amount; - body.levelJumpPower = 0; + case Stat.Acceleration: + body.baseAcceleration = reset ? ogBody.baseAcceleration : amount; break; - case Stat.Reset: - body.baseDamage = ogBody.baseDamage; - body.levelDamage = ogBody.levelDamage; - body.baseAttackSpeed = ogBody.baseAttackSpeed; - body.levelAttackSpeed = ogBody.levelAttackSpeed; - body.baseCrit = ogBody.baseCrit; - body.levelCrit = ogBody.levelCrit; - // - body.baseMaxHealth = ogBody.baseMaxHealth; - body.levelMaxHealth = ogBody.levelMaxHealth; - body.baseRegen = ogBody.baseRegen; - body.levelRegen = ogBody.levelRegen; - body.baseArmor = ogBody.baseArmor; - body.levelArmor = ogBody.levelArmor; - // - body.baseMoveSpeed = ogBody.baseMoveSpeed; - body.levelMoveSpeed = ogBody.levelMoveSpeed; - body.baseAcceleration = ogBody.baseAcceleration; - body.baseJumpPower = ogBody.baseJumpPower; - body.levelJumpPower = ogBody.levelJumpPower; + case Stat.JumpPower: + body.baseJumpPower = reset ? ogBody.baseJumpPower : amount; + body.levelJumpPower = reset ? ogBody.levelJumpPower : 0; break; } body.MarkAllStatsDirty(); diff --git a/Code/Lang.cs b/Code/Lang.cs index 585bde3..24cb604 100644 --- a/Code/Lang.cs +++ b/Code/Lang.cs @@ -31,7 +31,7 @@ public const string GIVEMONEY_ARGS = "Requires 1 argument: {amount} [target (player|'all')]", PLAYER_OR_ALL_OPTIONAL_ARGS = "Requires 0 argument: [target (player|'all'):]", PLAYER_OR_ALL_ARGS = "Requires 1 argument: {target (player|'all')}", - SETSTATS_ARGS = "Requires 1 argument: {amount} [target (player|'pinged'):]", + SETSTATS_ARGS = "Requires 1 argument: {stat} [amount|'reset'):'reset'] [target (player|'pinged'):]", PLAYER_OR_PINGED = "Requires 0 (1 if from server) arguments: [target (player|'pinged'):]", PLAYERPINGED_OR_ALL = "Requires 0 (1 if from server) arguments: [target (player|'pinged'|'all'):]", HEAL_ARGS = "Requires 1 argument: {amount} [target (player|'pinged'):]", @@ -108,8 +108,7 @@ public const string ALLMONEY_HELP = "Sets money to 2'000'000'000 for specified player. " + GIVEMONEY_ARGS, GOD_HELP = "Become invincible. " + ENABLE_ARGS, GODENEMY_HELP = "All monster team members become invincible. " + ENABLE_ARGS, - SETSTAT_HELP = "Sets the base stat to a specific value for yourself or target, and the level stat to 0. " + SETSTATS_ARGS, - RESETSTAT_HELP = "Resets the base & level stats for yourself or target", + SETSTAT_HELP = "Sets the base stat to the specified value, or reset it if no value given. Use respawn to undo all changes on self." + SETSTATS_ARGS, GIVEDRONE_HELP = "Summons the specified drone to a target. " + GIVEDRONE_ARGS, REMOVEALLDRONES_HELP = "Removes all drones from the target. " + REMOVEALLDRONES_ARGS, KILL_ALL_MINIONS_HELP = "Kills all minions owned by target. " + REMOVEALLDRONES_ARGS, From b0bd155ead353fac90e51479e5d48f4e75ec8a29 Mon Sep 17 00:00:00 2001 From: Wolfo Date: Sat, 10 Jan 2026 10:21:50 +0100 Subject: [PATCH 17/25] Removed 3 proposed commands due to redundancy. dtdamage: Too plain unlimited_junk: Too specific to need a toggle. kill_all_minions: Seems a bit too specific, I use kill_all 1 all the time I wouldn't switch over to this.. But remove_all_drones is good. --- CHANGELOG.md | 13 +++----- Code/AutoCompletion/AutoCompleteManager.cs | 2 ++ Code/DT-Commands/Drones.cs | 39 ---------------------- Code/DT-Commands/Macros.cs | 8 +---- Code/DT-Commands/PlayerCommands.cs | 23 ++++--------- Code/Lang.cs | 7 ++-- 6 files changed, 17 insertions(+), 75 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e17e66d..05407f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,12 +4,11 @@ * Added commands: * 'give_drone': Summons drone, specified amount and tier * 'remove_all_drones': Removes all drones, leaving no bodies. - * 'kill_all_minions': Kills all minions, leaving dead drones. * 'list_drone': List drone names and ids. - * 'set_ .. damage, attackspeed, crit, health, regen, armor, movespeed' Sets the stat to the specified value, for the target, for that life; For clean testing. - * 'reset_stats' Undoes changes from 'set_..' commands. - * 'nocooldowns': disables your skill cooldowns + * 'set_difficulty' Sets the runs selected difficulty. + * 'set_stat' Sets the given baseStat to the specified value, or resets it to the default value. For clean testing. + * 'nocooldowns': Toggles your skill cooldowns. * 'list_pickups': List pickup names and ids. * 'dump_mods': Lists all loaded mods and if they are tagged as RequiredByAll. Useful to get internal names to check for. @@ -26,7 +25,6 @@ * Added macro/short commands: * 'dtscanner': 100 BoostEquipmentRechrage & Radar Scanner equip for easy map searching. - * 'dtdamage': x1000000 damage macro. * 'dtpeace': 'kill_all Monster & Void', 'no_enemies true', 'god true' * 'dtcleanse': 'remove_all_buffs 0 & 1' & 'remove_all_dots' * 'random_equip' macro for 'give_equip random' @@ -35,8 +33,7 @@ * 'skill': shorthand for 'loadout_set_skill_variant self' * 'skin': shorthand for 'loadout_set_skin_variant self' * 'toggle_hud': toggle 'hud_enable' convar - * 'unlimited_junk': Toggle for 'junk_unlimited' and give 12 junk - + * Updated command functionality: * Item commands can now grant/remove channeled items * Item commands now mention you can type 0/1/2 instead of the name type. @@ -48,7 +45,7 @@ * 'give .. remove_buff' now accept negative amounts to remove/give, like item commands. * 'loadout_set_skill_variant' now accepts 'self' * 'random_items' changed default value to just give Tier1,2,3 - * 'hurt' third optional argument to bypass armor&damage calculations. + * 'hurt' third optional argument for direct damage. (bypassArmor bypassDamageCalcs). * 'kill_all' no value given now kills Monster & Void teams. * 'true_kill' now bypasses godmode and accepts 'pinged' & 'all' as target diff --git a/Code/AutoCompletion/AutoCompleteManager.cs b/Code/AutoCompletion/AutoCompleteManager.cs index e1122bc..4e11ada 100644 --- a/Code/AutoCompletion/AutoCompleteManager.cs +++ b/Code/AutoCompletion/AutoCompleteManager.cs @@ -73,6 +73,8 @@ internal static void RegisterAutoCompleteCommands() parser.RegisterStaticVariable("count", "count"); parser.RegisterStaticVariable("droneTier", "droneTier"); parser.RegisterStaticVariable("duration", "duration"); + parser.RegisterStaticVariable("skill_slot", "skill_slot"); + parser.RegisterStaticVariable("skill_variant", "skill_variant"); parser.RegisterStaticVariable("ai", MasterCatalog.allAiMasters.Select(i => $"{(int)i.masterIndex}|{i.name}|{StringFinder.GetLangInvar(StringFinder.GetMasterName(i))}"), 1); parser.RegisterStaticVariable("artifact", ArtifactCatalog.artifactDefs.Select(i => $"{(int)i.artifactIndex}|{i.cachedName}|{StringFinder.GetLangInvar(i.nameToken)}"), 1); parser.RegisterStaticVariable("difficulty", R2API.DifficultyAPI.difficultyDefinitions.Select(i => $"{(int)i.Key}|{StringFinder.GetLangInvar(i.Value.nameToken)}"), 1); diff --git a/Code/DT-Commands/Drones.cs b/Code/DT-Commands/Drones.cs index 5e2382e..224386b 100644 --- a/Code/DT-Commands/Drones.cs +++ b/Code/DT-Commands/Drones.cs @@ -156,44 +156,5 @@ private static void CCRemoveDrones(ConCommandArgs args) } Log.MessageNetworked(string.Format(Lang.REMOVEDRONES, removedAmount, target.name), args); } - - [ConCommand(commandName = "kill_all_minions", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.KILL_ALL_MINIONS_HELP)] - [AutoComplete(Lang.REMOVEALLDRONES_ARGS)] - private static void CCKillMinions(ConCommandArgs args) - { - if (!Run.instance) - { - Log.MessageNetworked(Lang.NOTINARUN_ERROR, args, LogLevel.MessageClientOnly); - return; - } - bool isDedicatedServer = args.sender == null; - if (isDedicatedServer && (args.Count < 1 || args[0] == Lang.DEFAULT_VALUE)) - { - Log.MessageNetworked(Lang.INSUFFICIENT_ARGS + Lang.PLAYER_ARGS, args, LogLevel.MessageClientOnly); - return; - } - - var target = Items.ParseTarget(args, 0); - if (target.failMessage != null) - { - Log.MessageNetworked(target.failMessage, args, LogLevel.MessageClientOnly); - return; - } - - var owner = target.inventory.GetComponent(); - if (owner == null || owner.group == null || owner.group.memberCount == 0) - { - Log.MessageNetworked(string.Format(Lang.Kill_MINIONS, target.name), args); - return; - } - for (int i = 0; i < owner.group.memberCount; i++) - { - var master = owner.group.members[i].GetComponent(); - master.TrueKill(); - } - Log.MessageNetworked(string.Format(Lang.Kill_MINIONS, target.name), args); - } - - } } diff --git a/Code/DT-Commands/Macros.cs b/Code/DT-Commands/Macros.cs index 4609a31..5becd9f 100644 --- a/Code/DT-Commands/Macros.cs +++ b/Code/DT-Commands/Macros.cs @@ -51,13 +51,7 @@ private static void Zoom(ConCommandArgs args) Invoke(args.sender, "give_item", "hoof", "20"); Invoke(args.sender, "give_item", "feather", "200"); } - - [ConCommand(commandName = "dtdamage", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.MACRO_DTDAMAGE_HELP)] - private static void Damage(ConCommandArgs args) - { - Invoke(args.sender, "give_item", "boostdamage", "9999990"); - } - + [ConCommand(commandName = "dtcleanse", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.MACRO_DTCLEANSE_HELP)] private static void CCCleanse(ConCommandArgs args) { diff --git a/Code/DT-Commands/PlayerCommands.cs b/Code/DT-Commands/PlayerCommands.cs index 65536b5..7214ce6 100644 --- a/Code/DT-Commands/PlayerCommands.cs +++ b/Code/DT-Commands/PlayerCommands.cs @@ -790,7 +790,8 @@ internal static bool UpdateCurrentPlayerBody(out NetworkUser networkUser, out Ch return false; } - [ConCommand(commandName = "skill", flags = ConVarFlags.ExecuteOnServer, helpText = "[skill_slot] [skill_variant]\nSets the skill variant for the sender's user profile.")] + [ConCommand(commandName = "skill", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.LOADOUTSKILL2_HELP)] + [AutoComplete(Lang.LOADOUTSKILL_ARGS)] public static void CCSetSkillShort(ConCommandArgs args) { args.userArgs = new List @@ -806,23 +807,7 @@ public static void CCSetSkinShort(ConCommandArgs args) { Macros.Invoke(args.sender, "loadout_set_skin_variant", "self", args.TryGetArgInt(0).GetValueOrDefault(-1).ToString()); } - - - [ConCommand(commandName = "unlimited_junk", flags = ConVarFlags.ExecuteOnServer, helpText = "Toggle junk_unlimited. Makes skillchecks ingore junk cost.")] - public static void CCToggleUnlimitedJunk(ConCommandArgs args) - { - JunkController.junkUnlimited.value = !JunkController.junkUnlimited.value; - if (JunkController.junkUnlimited.value) - { - Macros.Invoke(args.sender, "give_item", ((int)DLC3Content.Items.Junk.itemIndex).ToString(), "12"); - //Junk unlimited doesn't actually bypass the check. - //It just makes it not remove junk - } - Log.MessageNetworked(String.Format(JunkController.junkUnlimited.value ? Lang.SETTING_ENABLED : Lang.SETTING_DISABLED, "Unlimtied Junk"), args); - } - - [ConCommand(commandName = "nocooldowns", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.NOCOOLDOWN_HELP)] [AutoComplete(Lang.PLAYER_OR_PINGED)] @@ -848,6 +833,10 @@ public static void CCNoCooldowns(ConCommandArgs args) slot.cooldownOverride = 0; } } + if (NoCooldowns && slots[0].CalculateFinalRechargeInterval() > 0.001f) + { + //Some mod is preventing this command from working. + } string enable = NoCooldowns ? "Disabled" : "Reenabled"; Log.MessageNetworked($"{enable} Skill Cooldowns for {RoR2.Util.GetBestBodyName(target.body.gameObject)}", args); } diff --git a/Code/Lang.cs b/Code/Lang.cs index 24cb604..fe8b60f 100644 --- a/Code/Lang.cs +++ b/Code/Lang.cs @@ -111,8 +111,7 @@ public const string SETSTAT_HELP = "Sets the base stat to the specified value, or reset it if no value given. Use respawn to undo all changes on self." + SETSTATS_ARGS, GIVEDRONE_HELP = "Summons the specified drone to a target. " + GIVEDRONE_ARGS, REMOVEALLDRONES_HELP = "Removes all drones from the target. " + REMOVEALLDRONES_ARGS, - KILL_ALL_MINIONS_HELP = "Kills all minions owned by target. " + REMOVEALLDRONES_ARGS, - + HEAL_HELP = "Heal yourself or another target. " + HEAL_ARGS, HURT_HELP = "Deal generic damage to yourself or another target. " + HURT_ARGS, KICK_HELP = "Kicks the specified player from the session. " + PLAYER_ARGS, @@ -137,11 +136,11 @@ public const string LISTSURVIVOR_HELP = "List all survivors and their body/ai names. " + LISTQUERY_ARGS, LISTTEAM_HELP = "List all Teams and their language invariants. " + LISTQUERY_ARGS, LOADOUTSKIN_HELP = "Change your loadout's skin. " + LOADOUTSKIN_ARGS, + LOADOUTSKILL2_HELP = "Sets your loadout's skill variant for the given slot. " + LOADOUTSKILL_ARGS, LOCKEXP_HELP = "Prevent Experience gain. " + ENABLE_ARGS, NOCOOLDOWN_HELP = "Toggles skill cooldowns of the target. " + PLAYER_OR_PINGED, - MACRO_DTPEACE_HELP = "Kills all enemies, voids and disables enemies spawning.", + MACRO_DTPEACE_HELP = "Kills all enemies, voids, disables enemies spawning and enables godmode.", MACRO_DTZOOM_HELP = "Gives you 20 hooves and 200 feathers for getting around quickly.", - MACRO_DTDAMAGE_HELP = "Gives you a lot of BoostDamage hidden item.", MACRO_SCANNER_HELP = "Gives you 100 boostEquipmentRecharge and the Radar Scanner equipment to easily search stages.", MACRO_DTCLEANSE_HELP = "Removes all your buffs, timed buffs & dots.", From ee40a41403c53a1eb0e69fed327ae7e756048216 Mon Sep 17 00:00:00 2001 From: Wolfo Date: Fri, 16 Jan 2026 11:22:38 +0100 Subject: [PATCH 18/25] Small things Changed 'create_pickup' [search] to an enum Fixed an inconsistency with 'buddhaEnemy' 'charge_zone' default value 100%, instead of requiring you to give number. (Seems unnecessary to ask for number) Added dt style safety checks for 'loadout_set_skill_variant', 'skill', 'skin' --- CHANGELOG.md | 7 +-- Code/AutoCompletion/AutoCompleteManager.cs | 2 +- Code/DT-Commands/CurrentRun.cs | 9 ++-- Code/DT-Commands/Items.cs | 57 ++++++++++------------ Code/DT-Commands/PlayerCommands.cs | 15 ++++-- Code/Hooks.cs | 17 ++++++- Code/Lang.cs | 10 ++-- Code/StringFinder.cs | 5 +- 8 files changed, 70 insertions(+), 52 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 05407f3..da40649 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,16 +39,17 @@ * Item commands now mention you can type 0/1/2 instead of the name type. * 'spawn_interactable' now also shows interactable names in auto complete. * 'spawn_interactable' now accepts amount. - * 'create_pickup' now supports dropping drones & pickups. + * 'create_pickup' now supports dropping drones & pickups, and can use numbers to abbreviate search. * 'create_pickup' switched {search} and {permanent/temp} argument spots. * 'give_equip' now accepts '-1|none' to remove your equipment. * 'give .. remove_buff' now accept negative amounts to remove/give, like item commands. * 'loadout_set_skill_variant' now accepts 'self' * 'random_items' changed default value to just give Tier1,2,3 * 'hurt' third optional argument for direct damage. (bypassArmor bypassDamageCalcs). - * 'kill_all' no value given now kills Monster & Void teams. + * 'kill_all' default value now kills Monster & Void teams. * 'true_kill' now bypasses godmode and accepts 'pinged' & 'all' as target - + * 'charge_zone' default value now 100% charge. + * Fixed 'god 0/1'/'buddha 0/1' not setting the toggle's state. * Fixed 'loadout_set_skin_variant' crashing the game. diff --git a/Code/AutoCompletion/AutoCompleteManager.cs b/Code/AutoCompletion/AutoCompleteManager.cs index 4e11ada..a974c05 100644 --- a/Code/AutoCompletion/AutoCompleteManager.cs +++ b/Code/AutoCompletion/AutoCompleteManager.cs @@ -107,7 +107,7 @@ internal static void RegisterAutoCompleteCommands() parser.RegisterStaticVariable("item_type", CollectEnumNames(typeof(Items.ItemType), typeof(int)), 1); parser.RegisterStaticVariable("pickup_type", CollectEnumNames(typeof(Items.PickupType), typeof(int)), 1); - parser.RegisterStaticVariable("pickup_category", CollectEnumNames(typeof(Items.PickupCategory), typeof(int)), 1); + parser.RegisterStaticVariable("search", CollectEnumNames(typeof(Items.PickupSearch), typeof(int)), 1); parser.RegisterStaticVariable("stat", CollectEnumNames(typeof(PlayerCommands.Stat), typeof(int)), 1); diff --git a/Code/DT-Commands/CurrentRun.cs b/Code/DT-Commands/CurrentRun.cs index b806dc2..21db635 100644 --- a/Code/DT-Commands/CurrentRun.cs +++ b/Code/DT-Commands/CurrentRun.cs @@ -525,16 +525,13 @@ private static void CCChargeZone(ConCommandArgs args) Log.MessageNetworked(Lang.NOTINARUN_ERROR, args, LogLevel.MessageClientOnly); return; } - if (args.Count == 0) - { - Log.MessageNetworked(Lang.INSUFFICIENT_ARGS + Lang.CHARGEZONE_ARGS, args, LogLevel.MessageClientOnly); - return; - } - if (!TextSerialization.TryParseInvariant(args[0], out float charge)) + float charge = 100; + if (args.Count > 0 && !TextSerialization.TryParseInvariant(args[0], out charge)) { Log.MessageNetworked(string.Format(Lang.PARSE_ERROR, "charge", "float"), args, LogLevel.MessageClientOnly); return; } + Log.MessageNetworked(string.Format("Setting charge for all active holdout zones to {0}%", charge), args, LogLevel.Message); charge /= 100f; foreach (var zone in InstanceTracker.GetInstancesList()) diff --git a/Code/DT-Commands/Items.cs b/Code/DT-Commands/Items.cs index 938734f..8c8c59d 100644 --- a/Code/DT-Commands/Items.cs +++ b/Code/DT-Commands/Items.cs @@ -396,31 +396,16 @@ private static void CCCreatePickup(ConCommandArgs args) } } - bool searchEquip = true, searchItem = true, searchDrone = true, skip = false; + bool searchEquip = true, searchItem = true, searchDrone = true; + + PickupSearch searchType = PickupSearch.All; if (args.Count > 1 && args[1] != Lang.DEFAULT_VALUE) { - switch (args[1].ToUpperInvariant()) + searchType = ParsePickupSearch(args, 1); + if (searchType < PickupSearch.All || searchType >= PickupSearch.Count) { - case Lang.ALL: - break; - case Lang.PICKUP: - skip = true; - break; - case Lang.ITEM: - searchEquip = false; - searchDrone = false; - break; - case Lang.EQUIP: - searchItem = false; - searchDrone = false; - break; - case Lang.DRONE: - searchItem = false; - searchEquip = false; - break; - default: - Log.MessageNetworked(String.Format(Lang.INVALID_ARG_VALUE, "search"), args, LogLevel.MessageClientOnly); - return; + Log.MessageNetworked(String.Format(Lang.INVALID_ARG_VALUE, "search"), args, LogLevel.MessageClientOnly); + return; } } PickupIndex final = PickupIndex.none; @@ -437,7 +422,7 @@ private static void CCCreatePickup(ConCommandArgs args) final = PickupCatalog.FindPickupIndex("MiscPickupIndex.VoidCoin"); break; default: - if (skip) + if (searchType == PickupSearch.Pickup) { int? pickup2 = args.TryGetArgInt(0); if (pickup2 != null) @@ -450,16 +435,16 @@ private static void CCCreatePickup(ConCommandArgs args) } } else - { - if (searchEquip) + { + if (searchType == PickupSearch.All || searchType == PickupSearch.Item) { - equipment = StringFinder.Instance.GetEquipFromPartial(args[0]); + item = StringFinder.Instance.GetItemFromPartial(args[0]); } - if (searchItem) + if (searchType == PickupSearch.All || searchType == PickupSearch.Equip) { - item = StringFinder.Instance.GetItemFromPartial(args[0]); + equipment = StringFinder.Instance.GetEquipFromPartial(args[0]); } - if (searchDrone) + if (searchType == PickupSearch.All || searchType == PickupSearch.Drone) { drone = StringFinder.Instance.GetDroneFromPartial(args[0]); } @@ -765,13 +750,13 @@ internal enum PickupType Temp, Count, } - internal enum PickupCategory + internal enum PickupSearch { - Any, + All = -1, + Pickup, Item, Equip, Drone, - Pickup, Count, } @@ -845,6 +830,14 @@ private static PickupType ParsePickupType(ConCommandArgs args, int index) } return PickupType.Permanent; } + private static PickupSearch ParsePickupSearch(ConCommandArgs args, int index) + { + if (args.Count > index && args[index] != Lang.DEFAULT_VALUE) + { + return Enum.TryParse(args[index], true, out PickupSearch searchType) ? searchType : PickupSearch.All; + } + return PickupSearch.All; + } public static CommandTarget ParseTarget(ConCommandArgs args, int index) { diff --git a/Code/DT-Commands/PlayerCommands.cs b/Code/DT-Commands/PlayerCommands.cs index 7214ce6..d8429ec 100644 --- a/Code/DT-Commands/PlayerCommands.cs +++ b/Code/DT-Commands/PlayerCommands.cs @@ -790,10 +790,15 @@ internal static bool UpdateCurrentPlayerBody(out NetworkUser networkUser, out Ch return false; } - [ConCommand(commandName = "skill", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.LOADOUTSKILL2_HELP)] + [ConCommand(commandName = "skill", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.LOADOUTSKILL_SHORT_ARGS)] [AutoComplete(Lang.LOADOUTSKILL_ARGS)] public static void CCSetSkillShort(ConCommandArgs args) { + if (args.Count < 2) + { + Log.MessageNetworked(Lang.INSUFFICIENT_ARGS + Lang.LOADOUTSKILL_SHORT_ARGS, args, Log.LogLevel.MessageClientOnly); + return; + } args.userArgs = new List { "self", @@ -802,10 +807,14 @@ public static void CCSetSkillShort(ConCommandArgs args) }; UserProfile.CCLoadoutSetSkillVariant(args); } - [ConCommand(commandName = "skin", flags = ConVarFlags.ExecuteOnServer, helpText = "[skin_variant]\nSets the skin variant for the sender's user profile.")] + [ConCommand(commandName = "skin", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.LOADOUTSKIN_SHORT_ARGS)] public static void CCSetSkinShort(ConCommandArgs args) { - Macros.Invoke(args.sender, "loadout_set_skin_variant", "self", args.TryGetArgInt(0).GetValueOrDefault(-1).ToString()); + if (!TextSerialization.TryParseInvariant(args[0], out int requestedSkinIndexChange)) + { + Log.MessageNetworked(String.Format(Lang.PARSE_ERROR, "skin_index", "int"), args, LogLevel.MessageClientOnly); + } + Macros.Invoke(args.sender, "loadout_set_skin_variant", "self", requestedSkinIndexChange.ToString()); } diff --git a/Code/Hooks.cs b/Code/Hooks.cs index c164902..8c5e400 100644 --- a/Code/Hooks.cs +++ b/Code/Hooks.cs @@ -103,10 +103,25 @@ public static void InitializeHooks() On.RoR2.ConCommandArgExtensions.TryGetArgBodyIndex += AllowBodyIndexToBeUsedInsteadOfBodyName; On.RoR2.UserProfile.CCLoadoutSetSkillVariant += LoadoutSetSkillVariant_AcceptSELF; + On.RoR2.Run.CCRunSetStagesCleared += RunSetStagesCleared_SetLoopCountToo; + } + + private static void RunSetStagesCleared_SetLoopCountToo(On.RoR2.Run.orig_CCRunSetStagesCleared orig, ConCommandArgs args) + { + orig(args); + if (Run.instance) + { + Run.instance.Network_loopClearCount = Run.instance.NetworkstageClearCount / 5; + } } private static void LoadoutSetSkillVariant_AcceptSELF(On.RoR2.UserProfile.orig_CCLoadoutSetSkillVariant orig, ConCommandArgs args) { + if (args.Count < 3) + { + Log.MessageNetworked(Lang.INSUFFICIENT_ARGS + Lang.LOADOUTSKILL_ARGS, args, Log.LogLevel.MessageClientOnly); + return; + } string isSelf = args.TryGetArgString(0); if(isSelf != null && isSelf.ToUpperInvariant() == "SELF") { @@ -160,7 +175,7 @@ private static void SetBuddhaMode(On.RoR2.CharacterBody.orig_Start orig, Charact self.bodyFlags |= CharacterBody.BodyFlags.Buddha; } } - else if(buddhaMonsters && self.teamComponent && (self.teamComponent.teamIndex == TeamIndex.Monster || self.teamComponent.teamIndex == TeamIndex.Void)) + else if(buddhaMonsters && self.teamComponent && (self.teamComponent.teamIndex == TeamIndex.Monster)) { self.bodyFlags |= CharacterBody.BodyFlags.Buddha; } diff --git a/Code/Lang.cs b/Code/Lang.cs index fe8b60f..5d6661a 100644 --- a/Code/Lang.cs +++ b/Code/Lang.cs @@ -11,8 +11,8 @@ public const string BIND_ARGS = "Requires 2 arguments: {key} [console_commands]", BIND_DELETE_ARGS = "Requires 1 argument: {key}", CHANGETEAM_ARGS = "Requires 1 (2 if from server) argument: {team} [player:]", - CHARGEZONE_ARGS = "Requires 1 argument: {charge}", - CREATEPICKUP_ARGS = "Requires 1 (3 if from server) argument: {object (item|equip|drone|'lunarcoin'|'voidcoin')} [search ('item'|'equip'|'drone'|'all'|'pickup'):'all'] [pickup_type:'permanent'] player:]", + CHARGEZONE_ARGS = "Requires 0 argument: [charge:100]", + CREATEPICKUP_ARGS = "Requires 1 (3 if from server) argument: {object (item|equip|drone|'lunarcoin'|'voidcoin')} [search:'all'] [pickup_type:'permanent'] player:]", CREATEPOTENTIAL_ARGS = "Requires 0 (3 if from server) arguments: [droptable (droptable|'all'):'all'] [count:3] *[player:]", DELAY_ARGS = "Requires 2 arguments: {delay} {console_commands}", DUMPSTATE_ARGS = "Requires 0 (1 if from server) argument: [target (player|'pinged'):]", @@ -41,7 +41,9 @@ public const string LISTSKIN_ARGS = "Requires 0 arguments: [selection (body|'all'|'body'|'self'):'all']", LISTQUERY_ARGS = "Requires 0 arguments: [query]", LOADOUTSKIN_ARGS = "Requires 2 argument: {body_name (body|'self')} {skin_index}", - LOADOUTSKILL_ARGS = "Requires 2 argument: {skill_slot} {skill_variant}", + LOADOUTSKIN_SHORT_ARGS = "Requires 1 argument: {skin_index}", + LOADOUTSKILL_ARGS = "Requires 3 argument: {bodyIndex|'self'} {skill_slot} {skill_variant}", + LOADOUTSKILL_SHORT_ARGS = "Requires 2 argument: {skill_slot} {skill_variant}", NEXTBOSS_ARGS = "Requires 1 argument: {director_card} [count:1] [elite:None]", NEXTSTAGE_ARGS = "Requires 0 arguments: [specific_stage]", NO_ARGS = "Requires 0 arguments.", @@ -136,7 +138,7 @@ public const string LISTSURVIVOR_HELP = "List all survivors and their body/ai names. " + LISTQUERY_ARGS, LISTTEAM_HELP = "List all Teams and their language invariants. " + LISTQUERY_ARGS, LOADOUTSKIN_HELP = "Change your loadout's skin. " + LOADOUTSKIN_ARGS, - LOADOUTSKILL2_HELP = "Sets your loadout's skill variant for the given slot. " + LOADOUTSKILL_ARGS, + LOADOUTSKILL_HELP = "Sets your loadout's skill variant for the given slot. " + LOADOUTSKILL_SHORT_ARGS, LOCKEXP_HELP = "Prevent Experience gain. " + ENABLE_ARGS, NOCOOLDOWN_HELP = "Toggles skill cooldowns of the target. " + PLAYER_OR_PINGED, MACRO_DTPEACE_HELP = "Kills all enemies, voids, disables enemies spawning and enables godmode.", diff --git a/Code/StringFinder.cs b/Code/StringFinder.cs index 20d0bfa..2589249 100644 --- a/Code/StringFinder.cs +++ b/Code/StringFinder.cs @@ -314,10 +314,11 @@ public DifficultyIndex GetDifficultyFromPartial(string name) /// /// Matches either the exact (int)Index or Partial Invariant /// Returns an iterator with all DifficultyIndex's matched + /// Vanilla game has no DifficultyDef to DifficultyIndex. + /// Modded difficulties are not usually stored in DifficultyCatalog. + /// R2API is used instead. public IEnumerable GetDifficultiesFromPartial(string name) { - //Vanilla has no DifficultyDef -> Index - //Modded difficulties are also not stored in DifficultyCatalog usually. if (TextSerialization.TryParseInvariant(name, out int i)) { var index = (DifficultyIndex)i; From f4fc38c70c922a22be63a383743119e6909ba1f3 Mon Sep 17 00:00:00 2001 From: Wolfo Date: Fri, 16 Jan 2026 11:25:14 +0100 Subject: [PATCH 19/25] Buffs.TryParse Pinged fail message fix for real Did != instead of == oops --- Code/DT-Commands/Buffs.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/DT-Commands/Buffs.cs b/Code/DT-Commands/Buffs.cs index 6ea36ec..ca437b7 100644 --- a/Code/DT-Commands/Buffs.cs +++ b/Code/DT-Commands/Buffs.cs @@ -617,7 +617,7 @@ internal static CommandTarget ParseTarget(ConCommandArgs args, int index) target = targetMaster?.GetBody(); } } - if (target == null && failMessage != null) + if (target == null && failMessage == null) { failMessage = Lang.PLAYER_NOTFOUND; } From 03c08d32c0ff88e1632570d39c3e450a1e0714db Mon Sep 17 00:00:00 2001 From: Wolfo Date: Sat, 17 Jan 2026 09:10:05 +0100 Subject: [PATCH 20/25] Update CHANGELOG.md --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index da40649..18ebda3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,7 +39,8 @@ * Item commands now mention you can type 0/1/2 instead of the name type. * 'spawn_interactable' now also shows interactable names in auto complete. * 'spawn_interactable' now accepts amount. - * 'create_pickup' now supports dropping drones & pickups, and can use numbers to abbreviate search. + * 'spawn_ai' can use 'ally' instead of team, to spawn as a minion + * 'create_pickup' now supports dropping drones & pickups, and can use numbers to abbreviate search. * 'create_pickup' switched {search} and {permanent/temp} argument spots. * 'give_equip' now accepts '-1|none' to remove your equipment. * 'give .. remove_buff' now accept negative amounts to remove/give, like item commands. @@ -51,6 +52,8 @@ * 'charge_zone' default value now 100% charge. + * 'spawn_as' will set your permanent character again. + * 'run_set_stages_cleared' will now also set the loopClearCount. (Which is a seperate thing as of AC) * Fixed 'god 0/1'/'buddha 0/1' not setting the toggle's state. * Fixed 'loadout_set_skin_variant' crashing the game. * Modded spawn cards should be usable from the start now. From eece426a6ad2adfdf103f2272c72ff87ee8b8966 Mon Sep 17 00:00:00 2001 From: Wolfo Date: Sun, 18 Jan 2026 13:33:11 +0100 Subject: [PATCH 21/25] give_all_items {itemTier} Devs got a command like this, good for like crafting testing --- Code/DT-Commands/Items.cs | 52 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/Code/DT-Commands/Items.cs b/Code/DT-Commands/Items.cs index 8c8c59d..29fce96 100644 --- a/Code/DT-Commands/Items.cs +++ b/Code/DT-Commands/Items.cs @@ -289,6 +289,56 @@ private static void CCRandomItems(ConCommandArgs args) } } + [ConCommand(commandName = "give_all_items", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.GIVEALLITEMS_HELP)] + [AutoComplete(Lang.GIVEALLITEMS_ARGS)] + private static void CCGiveAllItems(ConCommandArgs args) + { + if (!Run.instance) + { + Log.MessageNetworked(Lang.NOTINARUN_ERROR, args, LogLevel.MessageClientOnly); + return; + } + bool isDedicatedServer = args.sender == null; + if (args.Count == 0 || (isDedicatedServer && (args.Count < 2 || args[1] == Lang.DEFAULT_VALUE))) + { + Log.MessageNetworked(Lang.INSUFFICIENT_ARGS + Lang.GIVEALLITEMS_ARGS, args, LogLevel.MessageClientOnly); + return; + } + + bool all = args[0].ToUpperInvariant() == Lang.ALL; + ItemTier itemTier = StringFinder.Instance.GetItemTierFromPartial(args[0]); + if (itemTier == StringFinder.ItemTier_NotFound) + { + Log.MessageNetworked(string.Format(Lang.OBJECT_NOTFOUND, "item tier", args[0]), args, LogLevel.MessageClientOnly); + return; + } + + var target = ParseTarget(args, 1); + if (target.failMessage != null) + { + Log.MessageNetworked(target.failMessage, args, LogLevel.MessageClientOnly); + return; + } + + for (int i = 0; i < ItemCatalog.allItemDefs.Length; i++) + { + ItemDef def = ItemCatalog.allItemDefs[i]; + if (!def.hidden) + { + if (all && def.tier != ItemTier.NoTier || def.tier == itemTier) + { + target.inventory.GiveItemPermanent(def); + } + } + } + if (target.devotionController) + { + target.devotionController.UpdateAllMinions(false); + } + Log.MessageNetworked($"Gave all items of tier(s) {args[0]} to {target.name}!", args); + } + + [ConCommand(commandName = "give_equip", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.GIVEEQUIP_HELP)] [AutoComplete(Lang.GIVEEQUIP_ARGS)] private static void CCGiveEquipment(ConCommandArgs args) @@ -1051,7 +1101,7 @@ internal static void CollectItemTiers(Run run) foreach (var itemIndex in ItemCatalog.allItems) { var itemDef = ItemCatalog.GetItemDef(itemIndex); - if (run.availableItems.Contains(itemIndex) && itemDef.DoesNotContainTag(ItemTag.WorldUnique)) + if (run.availableItems.Contains(itemIndex) || itemDef.tier == ItemTier.FoodTier || itemDef.DoesNotContainTag(ItemTag.WorldUnique)) { if (customTiers.TryGetValue(itemDef.tier, out var list)) { From 95d97ba460f8ecf8fc81fe8055b52fec88a4697a Mon Sep 17 00:00:00 2001 From: Wolfo Date: Sun, 18 Jan 2026 14:09:40 +0100 Subject: [PATCH 22/25] 'give_drone' -> `spawn_minion` 'remove_all_drones` -> `remove_all_minions` 'give_drone' -> Replaced with `spawn_minion` Maybe more agreeable overlap? And built upon already better code instead of more so duplicate. I just like being able to get the minion I want with 1 argument not 4 but that might not be too important. But other proposed commands are of similiar stature. Replaces elite with droneTier and axes the TeamIndex argument. If any other minion specific stuff might get added it could also just get added to this command yknow. --- Code/DT-Commands/Drones.cs | 160 ----------------------------- Code/DT-Commands/Lists.cs | 17 +++ Code/DT-Commands/PlayerCommands.cs | 43 ++++++++ Code/DT-Commands/Spawners.cs | 77 +++++++++----- 4 files changed, 112 insertions(+), 185 deletions(-) delete mode 100644 Code/DT-Commands/Drones.cs diff --git a/Code/DT-Commands/Drones.cs b/Code/DT-Commands/Drones.cs deleted file mode 100644 index 224386b..0000000 --- a/Code/DT-Commands/Drones.cs +++ /dev/null @@ -1,160 +0,0 @@ -using RoR2; -using System; -using System.Text; -using static DebugToolkit.Log; - -namespace DebugToolkit.Commands -{ - class Drones - { - [ConCommand(commandName = "list_drone", flags = ConVarFlags.None, helpText = Lang.LISTDRONE_HELP)] - [AutoComplete(Lang.LISTQUERY_ARGS)] - private static void CCListDrone(ConCommandArgs args) - { - var sb = new StringBuilder(); - var arg = args.Count > 0 ? args[0] : ""; - var indices = StringFinder.Instance.GetDronesFromPartial(arg); - foreach (var index in indices) - { - var definition = DroneCatalog.GetDroneDef(index); - var realName = Language.currentLanguage.GetLocalizedStringByToken(definition.nameToken); - bool enabled = Run.instance && Run.instance.IsDroneAvailable(index); - sb.AppendLine($"[{(int)index}]{definition.name} \"{realName}\" (enabled={enabled})"); - } - var s = sb.Length > 0 ? sb.ToString().TrimEnd('\n') : string.Format(Lang.NOMATCH_ERROR, "drone", arg); - Log.MessageNetworked(s, args, LogLevel.MessageClientOnly); - } - - [ConCommand(commandName = "give_drone", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.GIVEDRONE_HELP)] - [AutoComplete(Lang.GIVEDRONE_ARGS)] - private static void CCGiveDrone(ConCommandArgs args) - { - if (!Run.instance) - { - Log.MessageNetworked(Lang.NOTINARUN_ERROR, args, LogLevel.MessageClientOnly); - return; - } - bool isDedicatedServer = args.sender == null; - if (args.Count == 0 || (isDedicatedServer && (args.Count < 4 || args[3] == Lang.DEFAULT_VALUE))) - { - Log.MessageNetworked(Lang.INSUFFICIENT_ARGS + Lang.GIVEITEM_ARGS, args, LogLevel.MessageClientOnly); - return; - } - - int dCount = 1; - if (args.Count > 1 && args[1] != Lang.DEFAULT_VALUE && !TextSerialization.TryParseInvariant(args[1], out dCount)) - { - Log.MessageNetworked(String.Format(Lang.PARSE_ERROR, "count", "int"), args, LogLevel.MessageClientOnly); - return; - } - if (dCount < 0) - { - Log.MessageNetworked(string.Format(Lang.NEGATIVE_ARG, "count"), args, LogLevel.MessageClientOnly); - return; - } - int tier = 1; - if (args.Count > 2 && args[2] != Lang.DEFAULT_VALUE && !TextSerialization.TryParseInvariant(args[2], out tier)) - { - Log.MessageNetworked(String.Format(Lang.PARSE_ERROR, "droneTier", "int"), args, LogLevel.MessageClientOnly); - return; - } - if (tier < 0) - { - Log.MessageNetworked(string.Format(Lang.NEGATIVE_ARG, "droneTier"), args, LogLevel.MessageClientOnly); - return; - } - - var target = Buffs.ParseTarget(args, 3); - if (target.failMessage != null) - { - Log.MessageNetworked(target.failMessage, args, LogLevel.MessageClientOnly); - return; - } - - var drone = StringFinder.Instance.GetDroneFromPartial(args[0]); - DroneDef droneDef = DroneCatalog.GetDroneDef(drone); - if (drone == DroneIndex.None || !droneDef) - { - Log.MessageNetworked(string.Format(Lang.OBJECT_NOTFOUND, "drone", args[0]), args, LogLevel.MessageClientOnly); - return; - } - if (Run.instance.IsDroneExpansionLocked(drone)) - { - Log.MessageNetworked(string.Format(Lang.EXPANSION_LOCKED, "drone", Util.GetExpansion(droneDef.requiredExpansion)), args, LogLevel.MessageClientOnly); - return; - } - if (dCount > 0) - { - for (int i = 0; i < dCount; i++) - { - CharacterMaster newlySpawnedDrone = new MasterSummon - { - masterPrefab = droneDef.masterPrefab, - position = target.body.transform.position, - rotation = target.body.transform.rotation, - summonerBodyObject = target.body.gameObject, - ignoreTeamMemberLimit = true, - useAmbientLevel = true, - enablePrintController = true - }.Perform(); - if (tier > 1) - { - newlySpawnedDrone.inventory.GiveItemPermanent(DLC3Content.Items.DroneUpgradeHidden, (tier - 1)); - } - } - var name = droneDef.name; - Log.MessageNetworked(string.Format(Lang.GIVEDRONE, dCount, name, target.name, tier), args); - } - else - { - Log.MessageNetworked("Nothing happened", args); - } - - } - - - [ConCommand(commandName = "remove_all_drones", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.REMOVEALLDRONES_HELP)] - [AutoComplete(Lang.REMOVEALLDRONES_ARGS)] - private static void CCRemoveDrones(ConCommandArgs args) - { - if (!Run.instance) - { - Log.MessageNetworked(Lang.NOTINARUN_ERROR, args, LogLevel.MessageClientOnly); - return; - } - bool isDedicatedServer = args.sender == null; - if (isDedicatedServer && (args.Count < 1 || args[0] == Lang.DEFAULT_VALUE)) - { - Log.MessageNetworked(Lang.INSUFFICIENT_ARGS + Lang.REMOVEALLDRONES_ARGS, args, LogLevel.MessageClientOnly); - return; - } - - var target = Items.ParseTarget(args, 0); - if (target.failMessage != null) - { - Log.MessageNetworked(target.failMessage, args, LogLevel.MessageClientOnly); - return; - } - - - var owner = target.inventory.GetComponent(); - if (owner == null || owner.group == null || owner.group.memberCount == 0) - { - Log.MessageNetworked(string.Format(Lang.REMOVEDRONES, 0, target.name), args); - return; - } - int removedAmount = 0; - for (int i = 0; i < owner.group.memberCount; i++) - { - var master = owner.group.members[i].GetComponent(); - if (master.bodyPrefab.GetComponent().IsDrone) - { - master.DestroyBody(); - UnityEngine.Object.Destroy(master.gameObject, 1f); - removedAmount++; - } - } - Log.MessageNetworked(string.Format(Lang.REMOVEDRONES, removedAmount, target.name), args); - } - } -} diff --git a/Code/DT-Commands/Lists.cs b/Code/DT-Commands/Lists.cs index 1a73125..ff13ad2 100644 --- a/Code/DT-Commands/Lists.cs +++ b/Code/DT-Commands/Lists.cs @@ -88,6 +88,23 @@ private static void CCListDifficulty(ConCommandArgs args) Log.MessageNetworked(s, args, LogLevel.MessageClientOnly); } + [ConCommand(commandName = "list_drone", flags = ConVarFlags.None, helpText = Lang.LISTDRONE_HELP)] + [AutoComplete(Lang.LISTQUERY_ARGS)] + private static void CCListDrone(ConCommandArgs args) + { + var sb = new StringBuilder(); + var arg = args.Count > 0 ? args[0] : ""; + var indices = StringFinder.Instance.GetDronesFromPartial(arg); + foreach (var index in indices) + { + var definition = DroneCatalog.GetDroneDef(index); + var realName = Language.currentLanguage.GetLocalizedStringByToken(definition.nameToken); + bool enabled = Run.instance && Run.instance.IsDroneAvailable(index); + sb.AppendLine($"[{(int)index}]{definition.name} \"{realName}\" (enabled={enabled})"); + } + var s = sb.Length > 0 ? sb.ToString().TrimEnd('\n') : string.Format(Lang.NOMATCH_ERROR, "drone", arg); + Log.MessageNetworked(s, args, LogLevel.MessageClientOnly); + } [ConCommand(commandName = "list_ai", flags = ConVarFlags.None, helpText = Lang.LISTAI_HELP)] [AutoComplete(Lang.LISTQUERY_ARGS)] diff --git a/Code/DT-Commands/PlayerCommands.cs b/Code/DT-Commands/PlayerCommands.cs index d8429ec..d9c4d79 100644 --- a/Code/DT-Commands/PlayerCommands.cs +++ b/Code/DT-Commands/PlayerCommands.cs @@ -999,5 +999,48 @@ public static void SetStatsForBody(CharacterBody body, Stat stat, float amount, body.MarkAllStatsDirty(); } + + + [ConCommand(commandName = "remove_all_minions", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.REMOVEALLMINIONS_HELP)] + [AutoComplete(Lang.REMOVEALLMINIONS_ARGS)] + private static void CCRemoveDrones(ConCommandArgs args) + { + if (!Run.instance) + { + Log.MessageNetworked(Lang.NOTINARUN_ERROR, args, LogLevel.MessageClientOnly); + return; + } + bool isDedicatedServer = args.sender == null; + if (isDedicatedServer && (args.Count < 1 || args[0] == Lang.DEFAULT_VALUE)) + { + Log.MessageNetworked(Lang.INSUFFICIENT_ARGS + Lang.REMOVEALLMINIONS_ARGS, args, LogLevel.MessageClientOnly); + return; + } + + var target = Items.ParseTarget(args, 0); + if (target.failMessage != null) + { + Log.MessageNetworked(target.failMessage, args, LogLevel.MessageClientOnly); + return; + } + + + var owner = target.inventory.GetComponent(); + if (owner == null || owner.group == null || owner.group.memberCount == 0) + { + Log.MessageNetworked(string.Format(Lang.REMOVED_MINIONS, 0, target.name), args); + return; + } + int removedAmount = 0; + for (int i = 0; i < owner.group.memberCount; i++) + { + var master = owner.group.members[i].GetComponent(); + master.DestroyBody(); + UnityEngine.Object.Destroy(master.gameObject, 1f); + removedAmount++; + } + Log.MessageNetworked(string.Format(Lang.REMOVED_MINIONS, removedAmount, target.name), args); + } + } } diff --git a/Code/DT-Commands/Spawners.cs b/Code/DT-Commands/Spawners.cs index 74ff8e8..69a5fe9 100644 --- a/Code/DT-Commands/Spawners.cs +++ b/Code/DT-Commands/Spawners.cs @@ -169,9 +169,19 @@ private static void CCSpawnPortal(ConCommandArgs args) NetworkServer.Spawn(gameObject); } + [ConCommand(commandName = "spawn_minion", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.SPAWNMINION_HELP)] + [AutoComplete(Lang.SPAWNMINION_ARGS)] + private static void CCSpawnMinion(ConCommandArgs args) + { + CCSpawnCharacter(args, true); + } [ConCommand(commandName = "spawn_ai", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.SPAWNAI_HELP)] [AutoComplete(Lang.SPAWNAI_ARGS)] private static void CCSpawnAI(ConCommandArgs args) + { + CCSpawnCharacter(args, false); + } + private static void CCSpawnCharacter(ConCommandArgs args, bool spawnAsMinion) { if (!Run.instance) { @@ -209,23 +219,44 @@ private static void CCSpawnAI(ConCommandArgs args) return; } + int droneTier = 0; EliteDef eliteDef = null; if (args.Count > 2 && args[2] != Lang.DEFAULT_VALUE) { - var eliteIndex = StringFinder.Instance.GetEliteFromPartial(args[2]); - if (eliteIndex == StringFinder.EliteIndex_NotFound) + if (spawnAsMinion) { - Log.MessageNetworked(Lang.ELITE_NOTFOUND, args, LogLevel.MessageClientOnly); - return; + if (!TextSerialization.TryParseInvariant(args[2], out droneTier)) + { + Log.MessageNetworked(String.Format(Lang.PARSE_ERROR, "droneTier", "int"), args, LogLevel.MessageClientOnly); + return; + } + if (droneTier > 1 && Run.instance.IsItemExpansionLocked(DLC3Content.Items.DroneUpgradeHidden.itemIndex)) + { + Log.MessageNetworked("Tiered Minions require Alloyed Collective", args, LogLevel.WarningClientOnly); + } + if (droneTier < 0) + { + Log.MessageNetworked(string.Format(Lang.NEGATIVE_ARG, "droneTier"), args, LogLevel.MessageClientOnly); + return; + } } - eliteDef = EliteCatalog.GetEliteDef(eliteIndex); - if (eliteDef && eliteDef.eliteEquipmentDef && Run.instance.IsEquipmentExpansionLocked(eliteDef.eliteEquipmentDef.equipmentIndex)) + else { - var expansion = Util.GetExpansion(eliteDef.eliteEquipmentDef.requiredExpansion); - Log.MessageNetworked(string.Format(Lang.EXPANSION_LOCKED, "elite equipment", expansion), args, LogLevel.WarningClientOnly); + var eliteIndex = StringFinder.Instance.GetEliteFromPartial(args[2]); + if (eliteIndex == StringFinder.EliteIndex_NotFound) + { + Log.MessageNetworked(Lang.ELITE_NOTFOUND, args, LogLevel.MessageClientOnly); + return; + } + eliteDef = EliteCatalog.GetEliteDef(eliteIndex); + if (eliteDef && eliteDef.eliteEquipmentDef && Run.instance.IsEquipmentExpansionLocked(eliteDef.eliteEquipmentDef.equipmentIndex)) + { + var expansion = Util.GetExpansion(eliteDef.eliteEquipmentDef.requiredExpansion); + Log.MessageNetworked(string.Format(Lang.EXPANSION_LOCKED, "elite equipment", expansion), args, LogLevel.WarningClientOnly); + } } } - + bool braindead = false; if (args.Count > 3 && args[3] != Lang.DEFAULT_VALUE && !Util.TryParseBool(args[3], out braindead)) { @@ -233,23 +264,15 @@ private static void CCSpawnAI(ConCommandArgs args) return; } - bool isAlly = false; + TeamIndex teamIndex = TeamIndex.Monster; - if (args.Count > 4 && args[4] != Lang.DEFAULT_VALUE) + if (args.Count > 4 && args[4] != Lang.DEFAULT_VALUE && !spawnAsMinion) { - if (args[4].ToUpperInvariant() == Lang.ALLY) - { - isAlly = true; - teamIndex = args.senderBody.teamComponent.teamIndex; - } - else + teamIndex = StringFinder.Instance.GetTeamFromPartial(args[4]); + if (teamIndex == StringFinder.TeamIndex_NotFound) { - teamIndex = StringFinder.Instance.GetTeamFromPartial(args[4]); - if (teamIndex == StringFinder.TeamIndex_NotFound) - { - Log.MessageNetworked(Lang.TEAM_NOTFOUND, args, LogLevel.MessageClientOnly); - return; - } + Log.MessageNetworked(Lang.TEAM_NOTFOUND, args, LogLevel.MessageClientOnly); + return; } } @@ -277,8 +300,8 @@ private static void CCSpawnAI(ConCommandArgs args) }, RoR2Application.rng ); - spawnRequest.summonerBodyObject = isAlly ? args.senderBody.gameObject : null; - spawnRequest.teamIndexOverride = teamIndex; + spawnRequest.summonerBodyObject = spawnAsMinion ? args.senderBody.gameObject : null; + spawnRequest.teamIndexOverride = spawnAsMinion ? args.senderBody.teamComponent.teamIndex : teamIndex; spawnRequest.ignoreTeamMemberLimit = true; // The size of the monster's radius is required so multiple enemies do not spawn on the same spot. @@ -346,6 +369,10 @@ private static void CCSpawnAI(ConCommandArgs args) } master.aiComponents = Array.Empty(); } + if (droneTier > 1) + { + master.inventory.GiveItemPermanent(DLC3Content.Items.DroneUpgradeHidden, droneTier-1); + } } } } From 364caaa1da572cb8758336b877552b30967ea769 Mon Sep 17 00:00:00 2001 From: Wolfo Date: Sun, 18 Jan 2026 14:17:52 +0100 Subject: [PATCH 23/25] Misc consistency of proposed changes `toggle_hud` -> `hide_hud` consistency with hide_model and easier to type for me. `true_kill all` now actually does that. Lang for previous 2 commits. --- CHANGELOG.md | 37 ++++++++++++---------- Code/AutoCompletion/AutoCompleteManager.cs | 1 + Code/DT-Commands/LobbyManagement.cs | 10 +++--- Code/DT-Commands/PlayerCommands.cs | 3 +- Code/Lang.cs | 10 ++++-- 5 files changed, 34 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18ebda3..38b2e78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,44 +2,46 @@ * **3.22.0** * Added commands: - * 'give_drone': Summons drone, specified amount and tier - * 'remove_all_drones': Removes all drones, leaving no bodies. - * 'list_drone': List drone names and ids. - + * 'spawn_minion': Spawns characeter as your minion, specified amount and tier + * 'remove_all_minions': Removes all minions, leaving no bodies or broken ones. + * 'set_difficulty' Sets the runs selected difficulty. * 'set_stat' Sets the given baseStat to the specified value, or resets it to the default value. For clean testing. * 'nocooldowns': Toggles your skill cooldowns. + * 'list_drone': List drone names and ids. * 'list_pickups': List pickup names and ids. + * 'list_difficulty': List difficulty names and ids. * 'dump_mods': Lists all loaded mods and if they are tagged as RequiredByAll. Useful to get internal names to check for. + * 'godenemy': God mode for all monsters, to make them unhurtable. * 'buddhaenemy': Buddha mode for all monsters, to make them unkillable. - * 'goto_boss': Teleports you to boss, teleporter or boss arenas on stage, (so you don't have to fly to Mithrix 100 times) - * 'hide_model': hides model, for screenshotting/recording. - - * 'evolve_lemurians': Triggers Artifact of Devotion evolution. - * 'give_void': Gives Void Markers. - * 'no_interactables': Prevent interactables from spawning + * 'hide_model': Toggles your models visibiltiy, for screenshotting/recording. * 'toggle_time' Toggles 'time_scale' between 0 and what it it was before. - + * 'give_all_items' Gives all items of specified itemTier. + * 'give_void': Gives Void Markers. + * 'no_interactables': Prevent interactables from spawning + + * 'goto_boss': Teleports you to boss, teleporter or boss arenas on stage, (i.e. Skip directly to Mithrix on Moon2) + * 'evolve_lemurians': Triggers Artifact of Devotion evolution. + * Added macro/short commands: * 'dtscanner': 100 BoostEquipmentRechrage & Radar Scanner equip for easy map searching. * 'dtpeace': 'kill_all Monster & Void', 'no_enemies true', 'god true' * 'dtcleanse': 'remove_all_buffs 0 & 1' & 'remove_all_dots' - * 'random_equip' macro for 'give_equip random' + * 'random_equip' alternative for 'give_equip random' * 'rich', -> Set money to 2 billion. * 'poor' -> Set money to 0. * 'skill': shorthand for 'loadout_set_skill_variant self' * 'skin': shorthand for 'loadout_set_skin_variant self' - * 'toggle_hud': toggle 'hud_enable' convar - + * 'hide_hud': toggle 'hud_enable' convar + * Updated command functionality: * Item commands can now grant/remove channeled items * Item commands now mention you can type 0/1/2 instead of the name type. * 'spawn_interactable' now also shows interactable names in auto complete. * 'spawn_interactable' now accepts amount. - * 'spawn_ai' can use 'ally' instead of team, to spawn as a minion * 'create_pickup' now supports dropping drones & pickups, and can use numbers to abbreviate search. * 'create_pickup' switched {search} and {permanent/temp} argument spots. * 'give_equip' now accepts '-1|none' to remove your equipment. @@ -53,10 +55,11 @@ * 'spawn_as' will set your permanent character again. - * 'run_set_stages_cleared' will now also set the loopClearCount. (Which is a seperate thing as of AC) + * 'run_set_stages_cleared' will now also set the loopClearCount to the expected amount. (Which is a seperate thing as of AC) + * Modded spawn cards should be usable from the start now. + * Food items can now be given by {dropTable} * Fixed 'god 0/1'/'buddha 0/1' not setting the toggle's state. * Fixed 'loadout_set_skin_variant' crashing the game. - * Modded spawn cards should be usable from the start now. ### 3.21 ### diff --git a/Code/AutoCompletion/AutoCompleteManager.cs b/Code/AutoCompletion/AutoCompleteManager.cs index a974c05..fc796e1 100644 --- a/Code/AutoCompletion/AutoCompleteManager.cs +++ b/Code/AutoCompletion/AutoCompleteManager.cs @@ -81,6 +81,7 @@ internal static void RegisterAutoCompleteCommands() parser.RegisterStaticVariable("body", BodyCatalog.allBodyPrefabBodyBodyComponents.Select(i => $"{(int)i.bodyIndex}|{i.name}|{StringFinder.GetLangInvar(i.baseNameToken)}"), 1); parser.RegisterStaticVariable("buff", BuffCatalog.buffDefs.Select(i => $"{(int)i.buffIndex}|{StringFinder.GetLangInvar(i.name)}"), 1); parser.RegisterStaticVariable("droptable", ItemTierCatalog.allItemTierDefs.OrderBy(i => i.tier).Select(i => $"{(int)i.tier}|{i.name}"), 1); + parser.RegisterStaticVariable("itemTier", ItemTierCatalog.allItemTierDefs.OrderBy(i => i.tier).Select(i => $"{(int)i.tier}|{i.name}"), 1); parser.RegisterStaticVariable("dot", DotController.dotDefs.Select((d, i) => $"{i}|{(DotController.DotIndex)i}"), 1); parser.RegisterStaticVariable("elite", new string[] { "-1|None" }. Concat(EliteCatalog.eliteDefs.Select(i => $"{(int)i.eliteIndex}|{i.name}|{StringFinder.GetLangInvar(i.modifierToken)}")), diff --git a/Code/DT-Commands/LobbyManagement.cs b/Code/DT-Commands/LobbyManagement.cs index 6817e32..74e437b 100644 --- a/Code/DT-Commands/LobbyManagement.cs +++ b/Code/DT-Commands/LobbyManagement.cs @@ -60,13 +60,13 @@ private static void CCTrueKill(ConCommandArgs args) { if (args[0].ToUpperInvariant() == Lang.ALL) { - foreach (var player in PlayerCharacterMasterController.instances) + foreach (var _master in CharacterMaster.instancesList) { - player.master.godMode = false; - player.master.UpdateBodyGodMode(); - player.master.TrueKill(); + _master.godMode = false; + _master.UpdateBodyGodMode(); + _master.TrueKill(); } - Log.MessageNetworked("All players were killed by server.", args); + Log.MessageNetworked("All things were killed by server.", args); return; } else diff --git a/Code/DT-Commands/PlayerCommands.cs b/Code/DT-Commands/PlayerCommands.cs index d9c4d79..97e200b 100644 --- a/Code/DT-Commands/PlayerCommands.cs +++ b/Code/DT-Commands/PlayerCommands.cs @@ -875,7 +875,7 @@ public static void CCToggleModel(ConCommandArgs args) Log.MessageNetworked(String.Format(RoR2.UI.HUD.cvHudEnable.value ? Lang.SETTING_ENABLED : Lang.SETTING_DISABLED, "Hidden Model"), args, LogLevel.MessageClientOnly); } - [ConCommand(commandName = "toggle_hud", flags = ConVarFlags.None, helpText = Lang.TOGGLEHUD_HELP)] + [ConCommand(commandName = "hide_hud", flags = ConVarFlags.None, helpText = Lang.TOGGLEHUD_HELP)] public static void CCToggleHUD(ConCommandArgs args) { RoR2.UI.HUD.cvHudEnable.SetBool(!RoR2.UI.HUD.cvHudEnable.value); @@ -998,7 +998,6 @@ public static void SetStatsForBody(CharacterBody body, Stat stat, float amount, } body.MarkAllStatsDirty(); } - [ConCommand(commandName = "remove_all_minions", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.REMOVEALLMINIONS_HELP)] diff --git a/Code/Lang.cs b/Code/Lang.cs index 5d6661a..cd81ab7 100644 --- a/Code/Lang.cs +++ b/Code/Lang.cs @@ -26,7 +26,7 @@ public const string RANDOMEQUIP_ARGS = "Requires 0 (1 if from server) argument: [target (player|'pinged'):]", GIVEITEM_ARGS = "Requires 1 (3 if from server) argument: {item} [count:1] [item_type:'permanent'] [target (player|'pinged'|'evolution'|'simulacrum'|'voidfields'|'devotion'):]", GIVEDRONE_ARGS = "Requires 1 (4 if from server) argument: {drone} [count:1] [droneTier:1] [target (player|'pinged'):]", - REMOVEALLDRONES_ARGS = "Requires 0 (1 if from server) argument: [target (player|'pinged'):]", + REMOVEALLMINIONS_ARGS = "Requires 0 (1 if from server) argument: [target (player|'pinged'):]", GIVELUNAR_ARGS = "Requires 0 arguments: [amount:1]", GIVEMONEY_ARGS = "Requires 1 argument: {amount} [target (player|'all')]", PLAYER_OR_ALL_OPTIONAL_ARGS = "Requires 0 argument: [target (player|'all'):]", @@ -52,6 +52,7 @@ public const string RANDOMITEM_ARGS = "Requires 1 (3 if from server) argument: {count} [droptable (droptable|'all'):'\"Tier1:100,Tier2:60,Tier3:4\"'] [item_type:'permanent'] [target (player|'pinged'|'evolution'|'simulacrum'|'voidfields'|'devotion'):]", REMOVEALLBUFFS_ARGS = "Requires 0 (2 if from server) arguments: [timed (0|1):0/false] [target (player|'pinged'):]", REMOVEALLDOTS_ARGS = "Requires 0 (1 if from server) arguments: [target (player|'pinged'):]", + GIVEALLITEMS_ARGS = "Requires 1 (2 if from server) arguments: {itemTier (itemTier|'all')} [target (player|'pinged'|'evolution'|'simulacrum'|'voidfields'|'devotion'):]", REMOVEALLITEMS_ARGS = "Requires 0 (1 if from server) arguments: [target (player|'pinged'|'evolution'|'simulacrum'|'voidfields'|'devotion'):]", REMOVEBUFF_ARGS = "Requires 1 (4 if from server) arguments: {buff} [count:1] [timed (0|1):0/false] [target (player|'pinged'):]", REMOVEBUFFSTACKS_ARGS = "Requires 1 (3 if from server) arguments: {buff} [timed (0|1):0/false] [target (player|'pinged'):]", @@ -66,6 +67,7 @@ public const string SETARTIFACT_ARGS = "Requires 1 (2 if using 'all') argument: {artifact (artifact|'all')} [enable (0|1)]", SETDIFFICULTY_ARGS = "Requires 1 argument: {difficulty}", SPAWNAI_ARGS = "Requires 1 argument: {ai} [count:1] [elite:None] [braindead (0|1):0/false] [team (team|'ally'):Monster]", + SPAWNMINION_ARGS = "Requires 1 argument: {ai} [count:1] [droneTier:1] [braindead (0|1):0/false]", SPAWNAS_ARGS = "Requires 1 (2 if from server) argument: {body} [player:]", SPAWNBODY_ARGS = "Requires 1 argument: {body}", SPAWNINTERACTABLE_ARGS = "Requires 1 argument: {interactable} [count:1]", @@ -112,7 +114,7 @@ public const string GODENEMY_HELP = "All monster team members become invincible. " + ENABLE_ARGS, SETSTAT_HELP = "Sets the base stat to the specified value, or reset it if no value given. Use respawn to undo all changes on self." + SETSTATS_ARGS, GIVEDRONE_HELP = "Summons the specified drone to a target. " + GIVEDRONE_ARGS, - REMOVEALLDRONES_HELP = "Removes all drones from the target. " + REMOVEALLDRONES_ARGS, + REMOVEALLMINIONS_HELP = "Destroys the targets minions, leaving no bodies or broken ones. " + REMOVEALLMINIONS_ARGS, HEAL_HELP = "Heal yourself or another target. " + HEAL_ARGS, HURT_HELP = "Deal generic damage to yourself or another target. " + HURT_ARGS, @@ -163,6 +165,7 @@ public const string RELOADCONFIG_HELP = "Reload all default config files from all loaded plugins.", REMOVEALLBUFFS_HELP = "Removes all buffs from a character. " + REMOVEALLBUFFS_ARGS, REMOVEALLDOTS_HELP = "Removes all DoTs from a character. " + REMOVEALLDOTS_ARGS, + GIVEALLITEMS_HELP = "Gives all items of the tier to the target. " + GIVEALLITEMS_ARGS, REMOVEALLITEMS_HELP = "Removes all items from a target. " + REMOVEALLITEMS_ARGS, REMOVEBUFF_HELP = "Removes a specified buff from a character. Timed buffs prioritise the longest expiration stack. " + REMOVEBUFF_ARGS, REMOVEBUFFSTACKS_HELP = "Removes all stacks of a specified buff from a character. " + REMOVEBUFFSTACKS_ARGS, @@ -179,6 +182,7 @@ public const string SETDIFFICULTY_HELP = "Sets the runs selected difficulty. " + SETDIFFICULTY_ARGS, SPAWNAS_HELP = "Respawn the specified player using the specified body prefab. " + SPAWNAS_ARGS, SPAWNAI_HELP = "Spawns the specified CharacterMaster. " + SPAWNAI_ARGS, + SPAWNMINION_HELP = "Spawns the specified CharacterMaster as a minion. " + SPAWNMINION_ARGS, SPAWNBODY_HELP = "Spawns the specified dummy body. " + SPAWNBODY_ARGS, SPAWNINTERACTABLE_HELP = "Spawns the specified interactable. List_Interactable for options. " + SPAWNINTERACTABLE_ARGS, SPAWNPORTAL_HELP = "Spawns a portal in front of the player. " + SPAWNPORTAL_ARGS, @@ -200,7 +204,7 @@ public const string GIVEVOIDC_2 = "{0} {1} void marker(s).", GIVEOBJECT = "Gave {0} {1} to {2}.", GIVEDRONE = "Summoned {0} {1} (Tier {3}) to {2}.", - REMOVEDRONES = "Removed {0} drones from {1}.", + REMOVED_MINIONS = "Removed {0} minions from {1}.", REMOVEDEQUIP = "Removed current Equipment from {0}.", Kill_MINIONS = "Killed all minions owned by {0}.", OBSOLETEWARNING = "This command has become obsolete and will be removed in the next version. ", From c792d567704c79d263704acd9636c506c0f74424 Mon Sep 17 00:00:00 2001 From: Wolfo Date: Sun, 18 Jan 2026 15:26:08 +0100 Subject: [PATCH 24/25] 'spawn_portal' updated for DLC3 --- Code/AutoCompletion/AutoCompleteManager.cs | 1 + Code/DT-Commands/Items.cs | 5 ++- Code/DT-Commands/Spawners.cs | 45 ++++++++++++++++------ Code/Lang.cs | 4 +- 4 files changed, 40 insertions(+), 15 deletions(-) diff --git a/Code/AutoCompletion/AutoCompleteManager.cs b/Code/AutoCompletion/AutoCompleteManager.cs index fc796e1..d3a63c1 100644 --- a/Code/AutoCompletion/AutoCompleteManager.cs +++ b/Code/AutoCompletion/AutoCompleteManager.cs @@ -111,6 +111,7 @@ internal static void RegisterAutoCompleteCommands() parser.RegisterStaticVariable("search", CollectEnumNames(typeof(Items.PickupSearch), typeof(int)), 1); parser.RegisterStaticVariable("stat", CollectEnumNames(typeof(PlayerCommands.Stat), typeof(int)), 1); + parser.RegisterStaticVariable("portal", Spawners.portals.Select(i => $"{i.Key}"), 1); parser.Scan(System.Reflection.Assembly.GetExecutingAssembly()); } diff --git a/Code/DT-Commands/Items.cs b/Code/DT-Commands/Items.cs index 29fce96..7659d4f 100644 --- a/Code/DT-Commands/Items.cs +++ b/Code/DT-Commands/Items.cs @@ -306,8 +306,9 @@ private static void CCGiveAllItems(ConCommandArgs args) } bool all = args[0].ToUpperInvariant() == Lang.ALL; + bool consumed = args[0].ToUpperInvariant() == "CONSUMED"; ItemTier itemTier = StringFinder.Instance.GetItemTierFromPartial(args[0]); - if (itemTier == StringFinder.ItemTier_NotFound) + if (!all && !consumed && itemTier == StringFinder.ItemTier_NotFound) { Log.MessageNetworked(string.Format(Lang.OBJECT_NOTFOUND, "item tier", args[0]), args, LogLevel.MessageClientOnly); return; @@ -325,7 +326,7 @@ private static void CCGiveAllItems(ConCommandArgs args) ItemDef def = ItemCatalog.allItemDefs[i]; if (!def.hidden) { - if (all && def.tier != ItemTier.NoTier || def.tier == itemTier) + if (def.tier == itemTier || all && def.tier != ItemTier.NoTier || consumed && def.isConsumed) { target.inventory.GiveItemPermanent(def); } diff --git a/Code/DT-Commands/Spawners.cs b/Code/DT-Commands/Spawners.cs index 69a5fe9..2b6f516 100644 --- a/Code/DT-Commands/Spawners.cs +++ b/Code/DT-Commands/Spawners.cs @@ -13,7 +13,7 @@ namespace DebugToolkit.Commands { class Spawners { - private static readonly Dictionary portals = new Dictionary(); + public static readonly Dictionary portals = new Dictionary(); [ConCommand(commandName = "spawn_interactable", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.SPAWNINTERACTABLE_HELP)] [ConCommand(commandName = "spawn_interactible", flags = ConVarFlags.ExecuteOnServer, helpText = Lang.SPAWNINTERACTABLE_HELP)] @@ -142,13 +142,18 @@ private static void CCSpawnPortal(ConCommandArgs args) } var position = args.senderBody.footPosition; // Some portals spawn into the ground - if (portal.name == "DeepVoidPortal") - { - position.y += 4f; - } - else if (portal.name == "PortalArtifactworld") - { - position.y += 10f; + switch (portal.name) + { + case "DeepVoidPortal": + case "Encrypted": + case "Decrypted": + case "Mainline": + case "Virtaul": + position.y += 4f; + break; + case "PortalArtifactworld": + position.y += 10f; + break; } var gameObject = UnityEngine.Object.Instantiate(portal, position, Quaternion.LookRotation(args.senderBody.characterDirection.forward)); @@ -156,7 +161,16 @@ private static void CCSpawnPortal(ConCommandArgs args) // The artifact portal erroneously points to mysteryspace by default if (portalName == "artifact") { - exit.destinationScene = SceneCatalog.FindSceneDef("artifactworld"); + int num = UnityEngine.Random.Range(0, 4); + SceneDef sceneDef = SceneCatalog.FindSceneDef("artifactworld0" + num); + if (sceneDef && sceneDef.requiredExpansion && Run.instance.IsExpansionEnabled(sceneDef.requiredExpansion)) + { + exit.destinationScene = sceneDef; + } + else + { + exit.destinationScene = SceneCatalog.FindSceneDef("artifactworld"); + } } if (currentScene.cachedName == "voidraid" && gameObject.name.Contains("VoidOutroPortal")) { @@ -420,11 +434,20 @@ internal static void InitPortals() portals.Add("artifact", Addressables.LoadAssetAsync("RoR2/Base/PortalArtifactworld/PortalArtifactworld.prefab").WaitForCompletion()); portals.Add("blue", Addressables.LoadAssetAsync("RoR2/Base/PortalShop/PortalShop.prefab").WaitForCompletion()); portals.Add("celestial", Addressables.LoadAssetAsync("RoR2/Base/PortalMS/PortalMS.prefab").WaitForCompletion()); - portals.Add("deepvoid", Addressables.LoadAssetAsync("RoR2/DLC1/DeepVoidPortal/DeepVoidPortal.prefab").WaitForCompletion()); portals.Add("gold", Addressables.LoadAssetAsync("RoR2/Base/PortalGoldshores/PortalGoldshores.prefab").WaitForCompletion()); - portals.Add("green", Addressables.LoadAssetAsync("RoR2/DLC2/PortalColossus.prefab").WaitForCompletion()); portals.Add("null", Addressables.LoadAssetAsync("RoR2/Base/PortalArena/PortalArena.prefab").WaitForCompletion()); + //DLC1 portals.Add("void", Addressables.LoadAssetAsync("RoR2/DLC1/PortalVoid/PortalVoid.prefab").WaitForCompletion()); + portals.Add("deepvoid", Addressables.LoadAssetAsync("RoR2/DLC1/DeepVoidPortal/DeepVoidPortal.prefab").WaitForCompletion()); + portals.Add("simulacrum", Addressables.LoadAssetAsync("RoR2/DLC1/GameModes/InfiniteTowerRun/PortalInfiniteTower.prefab").WaitForCompletion()); + //DLC2 + portals.Add("green", Addressables.LoadAssetAsync("RoR2/DLC2/PortalColossus.prefab").WaitForCompletion()); + portals.Add("destination", Addressables.LoadAssetAsync("RoR2/DLC2/PM DestinationPortal.prefab").WaitForCompletion()); + //DLC3 + portals.Add("encrypted", Addressables.LoadAssetAsync("RoR2/DLC3/HardwareProgPortal.prefab").WaitForCompletion()); + portals.Add("decrypted", Addressables.LoadAssetAsync("RoR2/DLC3/SolusWebPortal.prefab").WaitForCompletion()); + portals.Add("virtual", Addressables.LoadAssetAsync("RoR2/DLC3/CompExchangePortal.prefab").WaitForCompletion()); + portals.Add("mainline", Addressables.LoadAssetAsync("RoR2/DLC3/EyePortal/EyePortal.prefab").WaitForCompletion()); } internal static CombatDirector.EliteTierDef GetTierDef(EliteDef eliteDef) diff --git a/Code/Lang.cs b/Code/Lang.cs index cd81ab7..6323ef0 100644 --- a/Code/Lang.cs +++ b/Code/Lang.cs @@ -52,7 +52,7 @@ public const string RANDOMITEM_ARGS = "Requires 1 (3 if from server) argument: {count} [droptable (droptable|'all'):'\"Tier1:100,Tier2:60,Tier3:4\"'] [item_type:'permanent'] [target (player|'pinged'|'evolution'|'simulacrum'|'voidfields'|'devotion'):]", REMOVEALLBUFFS_ARGS = "Requires 0 (2 if from server) arguments: [timed (0|1):0/false] [target (player|'pinged'):]", REMOVEALLDOTS_ARGS = "Requires 0 (1 if from server) arguments: [target (player|'pinged'):]", - GIVEALLITEMS_ARGS = "Requires 1 (2 if from server) arguments: {itemTier (itemTier|'all')} [target (player|'pinged'|'evolution'|'simulacrum'|'voidfields'|'devotion'):]", + GIVEALLITEMS_ARGS = "Requires 1 (2 if from server) arguments: {itemTier (itemTier|'consumed'|'all')} [target (player|'pinged'|'evolution'|'simulacrum'|'voidfields'|'devotion'):]", REMOVEALLITEMS_ARGS = "Requires 0 (1 if from server) arguments: [target (player|'pinged'|'evolution'|'simulacrum'|'voidfields'|'devotion'):]", REMOVEBUFF_ARGS = "Requires 1 (4 if from server) arguments: {buff} [count:1] [timed (0|1):0/false] [target (player|'pinged'):]", REMOVEBUFFSTACKS_ARGS = "Requires 1 (3 if from server) arguments: {buff} [timed (0|1):0/false] [target (player|'pinged'):]", @@ -71,7 +71,7 @@ public const string SPAWNAS_ARGS = "Requires 1 (2 if from server) argument: {body} [player:]", SPAWNBODY_ARGS = "Requires 1 argument: {body}", SPAWNINTERACTABLE_ARGS = "Requires 1 argument: {interactable} [count:1]", - SPAWNPORTAL_ARGS = "Requires 1 argument: {portal ('artifact'|'blue'|'celestial'|'deepvoid'|'gold'|'green'|'null'|'void')}", + SPAWNPORTAL_ARGS = "Requires 1 argument: {portal ('artifact'|'blue'|'celestial'|'deepvoid'|'gold'|'green'|'null'|'void'|'simulacrum'|'encrypted'|'decrypted'|'virtual'|'mainline')}", TIMESCALE_ARGS = "Requires 1 argument: {time_scale}" ; From 76445406efb8b4027ceefb7beff2a1610c6df185 Mon Sep 17 00:00:00 2001 From: Wolfo Date: Sun, 18 Jan 2026 15:48:45 +0100 Subject: [PATCH 25/25] Update Spawners.cs --- Code/DT-Commands/Spawners.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Code/DT-Commands/Spawners.cs b/Code/DT-Commands/Spawners.cs index 2b6f516..1278e8d 100644 --- a/Code/DT-Commands/Spawners.cs +++ b/Code/DT-Commands/Spawners.cs @@ -145,12 +145,13 @@ private static void CCSpawnPortal(ConCommandArgs args) switch (portal.name) { case "DeepVoidPortal": - case "Encrypted": - case "Decrypted": - case "Mainline": - case "Virtaul": position.y += 4f; break; + case "SolusWebPortal": + case "CompExchangePortal": + case "EyePortal": + position.y += 5f; + break; case "PortalArtifactworld": position.y += 10f; break;