diff --git a/DevourClient/ClientMain.cs b/DevourClient/ClientMain.cs
index 0640e32..b4f0903 100644
--- a/DevourClient/ClientMain.cs
+++ b/DevourClient/ClientMain.cs
@@ -51,6 +51,7 @@ namespace DevourClient
public static float exp = 1000f;
public static bool _walkInLobby = false;
public static bool infinite_mirrors = false;
+ static bool radialMenuEnabled = true;
static bool player_esp = false;
static bool player_skel_esp = false;
static bool player_snapline = false;
@@ -188,11 +189,9 @@ namespace DevourClient
fly = !fly;
}
- // Recall to base position (B key, only if enabled)
- if (recallEnabled && Input.GetKeyDown(KeyCode.B) && Player.IsInGameOrLobby())
- {
- Helpers.RecallHelper.RecallToBase();
- }
+ // Z-key radial menu logic is managed by RadialMenuManager
+ RadialMenuManager.Enabled = radialMenuEnabled;
+ RadialMenuManager.HandleUpdate();
if (Player.IsInGameOrLobby())
{
@@ -607,12 +606,15 @@ namespace DevourClient
}
}
- if (crosshair && in_game_cache)
- {
- const float crosshairSize = 4;
+ // End of EventType.Repaint branch
+ }
- float xMin = (Settings.Settings.width) - (crosshairSize / 2);
- float yMin = (Settings.Settings.height) - (crosshairSize / 2);
+ if (crosshair && in_game_cache)
+ {
+ const float crosshairSize = 4f;
+
+ float xMin = Settings.Settings.width - (crosshairSize / 2f);
+ float yMin = Settings.Settings.height - (crosshairSize / 2f);
if (crosshairTexture == null)
{
@@ -622,7 +624,8 @@ namespace DevourClient
GUI.DrawTexture(new Rect(xMin, yMin, crosshairSize, crosshairSize), crosshairTexture);
}
- }
+ // Radial menu rendering
+ RadialMenuManager.HandleOnGUI();
if (Settings.Settings.menu_enable)
{
@@ -2027,15 +2030,15 @@ namespace DevourClient
_walkInLobby = GUI.Toggle(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 155, 140, 20), _walkInLobby, MultiLanguageSystem.Translate("Walk In Lobby"));
_IsAutoRespawn = GUI.Toggle(new Rect(Settings.Settings.x + 160, Settings.Settings.y + 155, 140, 20), _IsAutoRespawn, MultiLanguageSystem.Translate("Auto Respawn"));
-
- fly = GUI.Toggle(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 190, 100, 20), fly, MultiLanguageSystem.Translate("Fly"));
- if (GUI.Button(new Rect(Settings.Settings.x + 120, Settings.Settings.y + 190, 60, 20), Settings.Settings.flyKey.ToString()))
+
+ fly = GUI.Toggle(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 180, 100, 20), fly, MultiLanguageSystem.Translate("Fly"));
+ if (GUI.Button(new Rect(Settings.Settings.x + 120, Settings.Settings.y + 180, 60, 20), Settings.Settings.flyKey.ToString()))
{
Settings.Settings.flyKey = Settings.Settings.GetKey();
}
- GUI.Label(new Rect(Settings.Settings.x + 20, Settings.Settings.y + 215, 80, 20), MultiLanguageSystem.Translate("Fly Speed") + ":");
- fly_speed = GUI.HorizontalSlider(new Rect(Settings.Settings.x + 100, Settings.Settings.y + 220, 150, 10), fly_speed, 5f, 20f);
- GUI.Label(new Rect(Settings.Settings.x + 260, Settings.Settings.y + 215, 50, 20), ((int)fly_speed).ToString());
+ GUI.Label(new Rect(Settings.Settings.x + 20, Settings.Settings.y + 205, 80, 20), MultiLanguageSystem.Translate("Fly Speed") + ":");
+ fly_speed = GUI.HorizontalSlider(new Rect(Settings.Settings.x + 100, Settings.Settings.y + 210, 150, 10), fly_speed, 5f, 20f);
+ GUI.Label(new Rect(Settings.Settings.x + 260, Settings.Settings.y + 205, 50, 20), ((int)fly_speed).ToString());
spoofLevel = GUI.Toggle(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 250, 200, 20), spoofLevel, MultiLanguageSystem.Translate("Spoof Level"));
GUI.Label(new Rect(Settings.Settings.x + 20, Settings.Settings.y + 275, 80, 20), MultiLanguageSystem.Translate("Level") + ":");
@@ -2053,8 +2056,8 @@ namespace DevourClient
GUI.Label(new Rect(Settings.Settings.x + 260, Settings.Settings.y + 395, 50, 20), ((int)_PlayerSpeedMultiplier).ToString());
showCoordinates = GUI.Toggle(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 430, 200, 20), showCoordinates, MultiLanguageSystem.Translate("Show Coordinates"));
-
- recallEnabled = GUI.Toggle(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 455, 200, 20), recallEnabled, MultiLanguageSystem.Translate("Recall (B)"));
+
+ radialMenuEnabled = GUI.Toggle(new Rect(Settings.Settings.x + 10, Settings.Settings.y + 455, 200, 20), radialMenuEnabled, MultiLanguageSystem.Translate("Radial Menu (Z)"));
// Display player coordinates at the bottom of Misc tab
if (showCoordinates && Player.IsInGameOrLobby())
diff --git a/DevourClient/ESP/ItemESPConfig.cs b/DevourClient/ESP/ItemESPConfig.cs
index 3d85e24..85ca850 100644
--- a/DevourClient/ESP/ItemESPConfig.cs
+++ b/DevourClient/ESP/ItemESPConfig.cs
@@ -2,9 +2,7 @@ using System.Collections.Generic;
namespace DevourClient.ESP
{
- ///
- /// Item ESP configuration management class - dynamically display different item types based on map
- ///
+ // Item ESP configuration management class - dynamically display different item types based on map
public static class ItemESPConfig
{
// ESP type enumeration
@@ -260,9 +258,6 @@ namespace DevourClient.ESP
{ ESPType.Collectables, false }
};
- ///
- /// Get list of ESP types supported by specified map
- ///
public static List GetMapESPTypes(string sceneName)
{
// If in menu, return empty list
@@ -284,35 +279,23 @@ namespace DevourClient.ESP
};
}
- ///
- /// Get ESP type enable status
- ///
public static bool GetESPState(ESPType type)
{
return espStates.ContainsKey(type) ? espStates[type] : false;
}
- ///
- /// Set ESP type enable status
- ///
public static void SetESPState(ESPType type, bool enabled)
{
if (espStates.ContainsKey(type))
espStates[type] = enabled;
}
- ///
- /// Toggle ESP type enable status
- ///
public static void ToggleESPState(ESPType type)
{
if (espStates.ContainsKey(type))
espStates[type] = !espStates[type];
}
- ///
- /// Get ESP type display name (for translation key)
- ///
public static string GetESPTypeName(ESPType type)
{
switch (type)
@@ -420,9 +403,6 @@ namespace DevourClient.ESP
}
}
- ///
- /// Get corresponding ESP type based on item name
- ///
public static ESPType? GetESPTypeByItemName(string itemName)
{
if (string.IsNullOrEmpty(itemName))
@@ -617,9 +597,6 @@ namespace DevourClient.ESP
}
}
- ///
- /// Check if ESP should be shown for specified item
- ///
public static bool ShouldShowESP(string itemName)
{
ESPType? espType = GetESPTypeByItemName(itemName);
@@ -629,9 +606,6 @@ namespace DevourClient.ESP
return GetESPState(espType.Value);
}
- ///
- /// Reset all ESP states
- ///
public static void ResetAllStates()
{
var keys = new List(espStates.Keys);
diff --git a/DevourClient/Helpers/RecallHelper.cs b/DevourClient/Helpers/RecallHelper.cs
deleted file mode 100644
index a46aa93..0000000
--- a/DevourClient/Helpers/RecallHelper.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-using UnityEngine;
-using MelonLoader;
-
-namespace DevourClient.Helpers
-{
- public static class RecallHelper
- {
- ///
- /// Teleports the local player to the base coordinates of the current map
- ///
- public static void RecallToBase()
- {
- try
- {
- Il2Cpp.NolanBehaviour nb = Player.GetPlayer();
- if (nb == null)
- {
- MelonLogger.Warning("Player not found!");
- return;
- }
-
- string sceneName = Map.GetActiveScene();
- Vector3 targetPos = Vector3.zero;
- string mapName = "";
-
- // Map coordinates based on scene name
- switch (sceneName)
- {
- case "Devour":
- case "Anna": // Farmhouse
- targetPos = new Vector3(5.03f, 4.20f, -50.02f);
- mapName = "Farm";
- break;
- case "Molly": // Asylum
- targetPos = new Vector3(17.52f, 1.38f, 7.04f);
- mapName = "Asylum";
- break;
- case "Inn":
- targetPos = new Vector3(3.53f, 0.84f, 2.47f);
- mapName = "Inn";
- break;
- case "Town":
- targetPos = new Vector3(-63.51f, 10.88f, -12.32f);
- mapName = "Town";
- break;
- case "Slaughterhouse":
- targetPos = new Vector3(6.09f, 0.70f, -17.58f);
- mapName = "Slaughterhouse";
- break;
- case "Manor":
- targetPos = new Vector3(3.67f, 1.32f, -23.34f);
- mapName = "Manor";
- break;
- case "Carnival":
- targetPos = new Vector3(-91.46f, 8.13f, -24.51f);
- mapName = "Carnival";
- break;
- default:
- MelonLogger.Warning($"Teleport not available for scene: {sceneName}");
- return;
- }
-
- // Teleport player to target position
- nb.locomotion.SetPosition(targetPos, false);
- MelonLogger.Msg($"Teleported to {mapName} coordinates: X:{targetPos.x:F2} Y:{targetPos.y:F2} Z:{targetPos.z:F2}");
- }
- catch (System.Exception ex)
- {
- MelonLogger.Error($"Failed to teleport: {ex.Message}");
- }
- }
- }
-}
-
diff --git a/DevourClient/Helpers/ReviveHelper.cs b/DevourClient/Helpers/ReviveHelper.cs
index 998d563..2a3360f 100644
--- a/DevourClient/Helpers/ReviveHelper.cs
+++ b/DevourClient/Helpers/ReviveHelper.cs
@@ -5,17 +5,13 @@ using UnityEngine;
namespace DevourClient.Helpers
{
- ///
- /// Shared revive utilities. When running as host we mirror DevourX's revive flow.
- ///
+ // Shared revive utilities. When running as host we mirror DevourX's revive flow.
public static class ReviveHelper
{
private static readonly Vector3 HostFallbackPosition = new Vector3(0f, -150f, 0f);
- ///
- /// Try to revive the provided NolanBehaviour using host-specific logic first,
- /// then fall back to the standard interactable flow.
- ///
+ // Try to revive the provided NolanBehaviour using host-specific logic first,
+ // then fall back to the standard interactable flow.
public static bool TryRevive(Il2Cpp.NolanBehaviour target)
{
if (target == null || target.gameObject == null)
@@ -88,11 +84,9 @@ namespace DevourClient.Helpers
return false;
}
- ///
- /// Legacy revive method migrated from StateHelper.BasePlayer.Revive().
- /// This method preserves the original implementation from StateHelper.
- ///
- /// The GameObject of the player to revive
+ // Legacy revive method migrated from StateHelper.BasePlayer.Revive().
+ // This method preserves the original implementation from StateHelper.
+ // targetGameObject: The GameObject of the player to revive.
public static void ReviveLegacy(GameObject targetGameObject)
{
if (targetGameObject == null)
diff --git a/DevourClient/Localization/Translations/ChineseTranslations.cs b/DevourClient/Localization/Translations/ChineseTranslations.cs
index 171264e..6a2cdcd 100644
--- a/DevourClient/Localization/Translations/ChineseTranslations.cs
+++ b/DevourClient/Localization/Translations/ChineseTranslations.cs
@@ -207,6 +207,7 @@ namespace DevourClient.Localization.Translations
{ "Rat ESP", "老鼠透视" },
{ "Region", "区域" },
{ "Revive", "复活" },
+ { "Radial Menu (Z)", "轮盘菜单 (Z)" },
{ "Ritual Book", "仪式书" },
{ "Rose", "玫瑰" },
{ "Ritual Book ESP", "仪式书透视" },
@@ -253,8 +254,11 @@ namespace DevourClient.Localization.Translations
{ "TP to Azazel", "传送到 Azazel" },
{ "TV", "电视" },
{ "Teleport Keys", "传送钥匙" },
- { "Recall (B)", "回城 (B)" },
{ "Teleport to", "传送至" },
+ { "TP Base", "传送至基地" },
+ { "TP Altar", "传送至祭坛" },
+ { "TP Basin", "传送至水池" },
+ { "TP Fountain", "传送至喷泉" },
{ "Ticket", "票券" },
{ "Town", "小镇" },
{ "TownDoor", "小镇门" },
diff --git a/DevourClient/Localization/Translations/EnglishTranslations.cs b/DevourClient/Localization/Translations/EnglishTranslations.cs
index 81e2652..8b757cc 100644
--- a/DevourClient/Localization/Translations/EnglishTranslations.cs
+++ b/DevourClient/Localization/Translations/EnglishTranslations.cs
@@ -207,6 +207,7 @@ namespace DevourClient.Localization.Translations
{ "Rat ESP", "Rat ESP" },
{ "Region", "Region" },
{ "Revive", "Revive" },
+ { "Radial Menu (Z)", "Radial Menu (Z)" },
{ "Ritual Book", "Ritual Book" },
{ "Rose", "Rose" },
{ "Ritual Book ESP", "Ritual Book ESP" },
@@ -253,8 +254,11 @@ namespace DevourClient.Localization.Translations
{ "TP to Azazel", "TP to Azazel" },
{ "TV", "TV" },
{ "Teleport Keys", "Teleport Keys" },
- { "Recall (B)", "Recall (B)" },
{ "Teleport to", "Teleport to" },
+ { "TP Base", "TP Base" },
+ { "TP Altar", "TP Altar" },
+ { "TP Basin", "TP Basin" },
+ { "TP Fountain", "TP Fountain" },
{ "Ticket", "Ticket" },
{ "Town", "Town" },
{ "TownDoor", "TownDoor" },
diff --git a/DevourClient/Localization/Translations/FrenchTranslations.cs b/DevourClient/Localization/Translations/FrenchTranslations.cs
index 7cd018d..aec9591 100644
--- a/DevourClient/Localization/Translations/FrenchTranslations.cs
+++ b/DevourClient/Localization/Translations/FrenchTranslations.cs
@@ -207,6 +207,7 @@ namespace DevourClient.Localization.Translations
{ "Rat ESP", "ESP rat" },
{ "Region", "Région" },
{ "Revive", "Réanimer" },
+ { "Radial Menu (Z)", "Menu radial (Z)" },
{ "Ritual Book", "Livre rituel" },
{ "Rose", "Rose" },
{ "Ritual Book ESP", "ESP livre rituel" },
@@ -253,8 +254,11 @@ namespace DevourClient.Localization.Translations
{ "TP to Azazel", "TP vers Azazel" },
{ "TV", "Télévision" },
{ "Teleport Keys", "Téléporter clés" },
- { "Recall (B)", "Retour (B)" },
{ "Teleport to", "Téléporter" },
+ { "TP Base", "TP base" },
+ { "TP Altar", "TP autel" },
+ { "TP Basin", "TP bassin" },
+ { "TP Fountain", "TP fontaine" },
{ "Ticket", "Billet" },
{ "Town", "Ville" },
{ "TownDoor", "Porte de ville" },
diff --git a/DevourClient/Localization/Translations/GermanTranslations.cs b/DevourClient/Localization/Translations/GermanTranslations.cs
index ce92af4..da22c2b 100644
--- a/DevourClient/Localization/Translations/GermanTranslations.cs
+++ b/DevourClient/Localization/Translations/GermanTranslations.cs
@@ -207,6 +207,7 @@ namespace DevourClient.Localization.Translations
{ "Rat ESP", "Ratte-ESP" },
{ "Region", "Region" },
{ "Revive", "Wiederbeleben" },
+ { "Radial Menu (Z)", "Radiales Menü (Z)" },
{ "Ritual Book", "Ritualbuch" },
{ "Rose", "Rose" },
{ "Ritual Book ESP", "Ritualbuch-ESP" },
@@ -253,8 +254,11 @@ namespace DevourClient.Localization.Translations
{ "TP to Azazel", "TP zu Azazel" },
{ "TV", "Fernseher" },
{ "Teleport Keys", "Schlüssel teleportieren" },
- { "Recall (B)", "Zurückrufen (B)" },
{ "Teleport to", "Teleportieren" },
+ { "TP Base", "TP Basis" },
+ { "TP Altar", "TP Altar" },
+ { "TP Basin", "TP Becken" },
+ { "TP Fountain", "TP Brunnen" },
{ "Ticket", "Ticket" },
{ "Town", "Stadt" },
{ "TownDoor", "Stadttür" },
diff --git a/DevourClient/Localization/Translations/ItalianTranslations.cs b/DevourClient/Localization/Translations/ItalianTranslations.cs
index 0fc98d0..246a6f7 100644
--- a/DevourClient/Localization/Translations/ItalianTranslations.cs
+++ b/DevourClient/Localization/Translations/ItalianTranslations.cs
@@ -207,6 +207,7 @@ namespace DevourClient.Localization.Translations
{ "Rat ESP", "ESP ratto" },
{ "Region", "Regione" },
{ "Revive", "Rianima" },
+ { "Radial Menu (Z)", "Menu radiale (Z)" },
{ "Ritual Book", "Libro rituale" },
{ "Rose", "Rosa" },
{ "Ritual Book ESP", "ESP libro rituale" },
@@ -253,8 +254,11 @@ namespace DevourClient.Localization.Translations
{ "TP to Azazel", "TP ad Azazel" },
{ "TV", "Televisione" },
{ "Teleport Keys", "Teletrasporta chiavi" },
- { "Recall (B)", "Richiama (B)" },
{ "Teleport to", "Teletrasporta" },
+ { "TP Base", "TP Base" },
+ { "TP Altar", "TP Altare" },
+ { "TP Basin", "TP Bacino" },
+ { "TP Fountain", "TP Fontana" },
{ "Ticket", "Biglietto" },
{ "Town", "Città" },
{ "TownDoor", "Porta della città" },
diff --git a/DevourClient/Localization/Translations/JapaneseTranslations.cs b/DevourClient/Localization/Translations/JapaneseTranslations.cs
index 549f423..3af4799 100644
--- a/DevourClient/Localization/Translations/JapaneseTranslations.cs
+++ b/DevourClient/Localization/Translations/JapaneseTranslations.cs
@@ -207,6 +207,7 @@ namespace DevourClient.Localization.Translations
{ "Rat ESP", "ネズミESP" },
{ "Region", "地域" },
{ "Revive", "蘇生" },
+ { "Radial Menu (Z)", "ラジアルメニュー (Z)" },
{ "Ritual Book", "儀式の本" },
{ "Rose", "バラ" },
{ "Ritual Book ESP", "儀式の本ESP" },
@@ -253,8 +254,11 @@ namespace DevourClient.Localization.Translations
{ "TP to Azazel", "Azazelへテレポート" },
{ "TV", "テレビ" },
{ "Teleport Keys", "鍵をテレポート" },
- { "Recall (B)", "リコール (B)" },
{ "Teleport to", "テレポート" },
+ { "TP Base", "ベースTP" },
+ { "TP Altar", "祭壇TP" },
+ { "TP Basin", "水盤TP" },
+ { "TP Fountain", "噴水TP" },
{ "Ticket", "チケット" },
{ "Town", "町" },
{ "TownDoor", "町のドア" },
diff --git a/DevourClient/Localization/Translations/KoreanTranslations.cs b/DevourClient/Localization/Translations/KoreanTranslations.cs
index c540ead..13ab649 100644
--- a/DevourClient/Localization/Translations/KoreanTranslations.cs
+++ b/DevourClient/Localization/Translations/KoreanTranslations.cs
@@ -207,6 +207,7 @@ namespace DevourClient.Localization.Translations
{ "Rat ESP", "쥐 ESP" },
{ "Region", "지역" },
{ "Revive", "부활" },
+ { "Radial Menu (Z)", "방사형 메뉴 (Z)" },
{ "Ritual Book", "의식서" },
{ "Rose", "장미" },
{ "Ritual Book ESP", "의식서 ESP" },
@@ -253,8 +254,11 @@ namespace DevourClient.Localization.Translations
{ "TP to Azazel", "Azazel로 텔레포트" },
{ "TV", "TV" },
{ "Teleport Keys", "열쇠 텔레포트" },
- { "Recall (B)", "리콜 (B)" },
{ "Teleport to", "텔레포트" },
+ { "TP Base", "기지 TP" },
+ { "TP Altar", "제단 TP" },
+ { "TP Basin", "대야 TP" },
+ { "TP Fountain", "분수 TP" },
{ "Ticket", "티켓" },
{ "Town", "마을" },
{ "TownDoor", "마을 문" },
diff --git a/DevourClient/Localization/Translations/PortugueseTranslations.cs b/DevourClient/Localization/Translations/PortugueseTranslations.cs
index bd32b53..b5fae02 100644
--- a/DevourClient/Localization/Translations/PortugueseTranslations.cs
+++ b/DevourClient/Localization/Translations/PortugueseTranslations.cs
@@ -207,6 +207,7 @@ namespace DevourClient.Localization.Translations
{ "Rat ESP", "ESP rato" },
{ "Region", "Região" },
{ "Revive", "Reviver" },
+ { "Radial Menu (Z)", "Menu radial (Z)" },
{ "Ritual Book", "Livro ritual" },
{ "Rose", "Rosa" },
{ "Ritual Book ESP", "ESP livro ritual" },
@@ -253,8 +254,11 @@ namespace DevourClient.Localization.Translations
{ "TP to Azazel", "TP para Azazel" },
{ "TV", "Televisão" },
{ "Teleport Keys", "Teletransportar chaves" },
- { "Recall (B)", "Recuar (B)" },
{ "Teleport to", "Teletransportar" },
+ { "TP Base", "TP base" },
+ { "TP Altar", "TP altar" },
+ { "TP Basin", "TP bacia" },
+ { "TP Fountain", "TP fonte" },
{ "Ticket", "Bilhete" },
{ "Town", "Cidade" },
{ "TownDoor", "Porta da cidade" },
diff --git a/DevourClient/Localization/Translations/RussianTranslations.cs b/DevourClient/Localization/Translations/RussianTranslations.cs
index 4ffcf38..f7e036c 100644
--- a/DevourClient/Localization/Translations/RussianTranslations.cs
+++ b/DevourClient/Localization/Translations/RussianTranslations.cs
@@ -207,6 +207,7 @@ namespace DevourClient.Localization.Translations
{ "Rat ESP", "ESP крысы" },
{ "Region", "Регион" },
{ "Revive", "Воскресить" },
+ { "Radial Menu (Z)", "Радиальное меню (Z)" },
{ "Ritual Book", "Ритуальная книга" },
{ "Rose", "Роза" },
{ "Ritual Book ESP", "ESP ритуальной книги" },
@@ -253,8 +254,11 @@ namespace DevourClient.Localization.Translations
{ "TP to Azazel", "ТП к Azazel" },
{ "TV", "Телевизор" },
{ "Teleport Keys", "Телепорт ключей" },
- { "Recall (B)", "Возврат (B)" },
{ "Teleport to", "Телепорт" },
+ { "TP Base", "ТП база" },
+ { "TP Altar", "ТП алтарь" },
+ { "TP Basin", "ТП чаша" },
+ { "TP Fountain", "ТП фонтан" },
{ "Ticket", "Билет" },
{ "Town", "Город" },
{ "TownDoor", "Дверь города" },
diff --git a/DevourClient/Localization/Translations/SpanishTranslations.cs b/DevourClient/Localization/Translations/SpanishTranslations.cs
index 2592a09..0571f84 100644
--- a/DevourClient/Localization/Translations/SpanishTranslations.cs
+++ b/DevourClient/Localization/Translations/SpanishTranslations.cs
@@ -207,6 +207,7 @@ namespace DevourClient.Localization.Translations
{ "Rat ESP", "ESP rata" },
{ "Region", "Región" },
{ "Revive", "Revivir" },
+ { "Radial Menu (Z)", "Menú radial (Z)" },
{ "Ritual Book", "Libro ritual" },
{ "Rose", "Rosa" },
{ "Ritual Book ESP", "ESP libro ritual" },
@@ -253,8 +254,11 @@ namespace DevourClient.Localization.Translations
{ "TP to Azazel", "TP a Azazel" },
{ "TV", "Televisión" },
{ "Teleport Keys", "Teletransportar llaves" },
- { "Recall (B)", "Regresar (B)" },
{ "Teleport to", "Teletransportar" },
+ { "TP Base", "TP base" },
+ { "TP Altar", "TP altar" },
+ { "TP Basin", "TP pila" },
+ { "TP Fountain", "TP fuente" },
{ "Ticket", "Boleto" },
{ "Town", "Pueblo" },
{ "TownDoor", "Puerta de pueblo" },
diff --git a/DevourClient/Localization/Translations/VietnameseTranslations.cs b/DevourClient/Localization/Translations/VietnameseTranslations.cs
index 1ad95d5..b58dc59 100644
--- a/DevourClient/Localization/Translations/VietnameseTranslations.cs
+++ b/DevourClient/Localization/Translations/VietnameseTranslations.cs
@@ -207,6 +207,7 @@ namespace DevourClient.Localization.Translations
{ "Rat ESP", "Chuột ESP" },
{ "Region", "Khu vực" },
{ "Revive", "Hồi sinh" },
+ { "Radial Menu (Z)", "Menu vòng tròn (Z)" },
{ "Ritual Book", "Sách nghi lễ" },
{ "Rose", "Hoa hồng" },
{ "Ritual Book ESP", "Sách nghi lễ ESP" },
@@ -253,8 +254,11 @@ namespace DevourClient.Localization.Translations
{ "TP to Azazel", "TP đến Azazel" },
{ "TV", "TV" },
{ "Teleport Keys", "Phím dịch chuyển" },
- { "Recall (B)", "Triệu hồi (B)" },
{ "Teleport to", "Dịch chuyển đến" },
+ { "TP Base", "TP căn cứ" },
+ { "TP Altar", "TP bàn thờ" },
+ { "TP Basin", "TP bể nước" },
+ { "TP Fountain", "TP đài phun nước" },
{ "Ticket", "Vé" },
{ "Town", "Town" },
{ "TownDoor", "TownDoor" },
diff --git a/DevourClient/Network/LobbyManager.cs b/DevourClient/Network/LobbyManager.cs
index ee35181..747e5b6 100644
--- a/DevourClient/Network/LobbyManager.cs
+++ b/DevourClient/Network/LobbyManager.cs
@@ -8,17 +8,13 @@ using UnityEngine;
namespace DevourClient.Network
{
- ///
- /// Lobby creation and management class
- ///
+ // Lobby creation and management class
public static class LobbyManager
{
- ///
- /// Create game lobby/room
- ///
- /// Region code (e.g.: "eu", "us", "asia", "usw", "sa", "jp", "au", "ru", "in", "kr")
- /// Maximum player limit (1-64)
- /// Whether this is a private room
+ // Create game lobby/room.
+ // regionCode: Region code (e.g.: "eu", "us", "asia", "usw", "sa", "jp", "au", "ru", "in", "kr").
+ // lobbyLimit: Maximum player limit (1-64).
+ // isPrivate: Whether this is a private room.
public static void CreateLobby(string regionCode, int lobbyLimit, bool isPrivate)
{
try
@@ -96,9 +92,6 @@ namespace DevourClient.Network
}
}
- ///
- /// Get PhotonRegion object for specified region
- ///
private static PhotonRegion GetPhotonRegion(string regionCode)
{
try
@@ -113,9 +106,6 @@ namespace DevourClient.Network
}
}
- ///
- /// Find Menu controller
- ///
private static Il2CppHorror.Menu FindMenuController()
{
try
@@ -142,9 +132,6 @@ namespace DevourClient.Network
}
}
- ///
- /// Check if in game
- ///
private static bool IsInGame()
{
try
@@ -159,9 +146,6 @@ namespace DevourClient.Network
}
}
- ///
- /// Force start lobby game (host only)
- ///
public static void ForceLobbyStart()
{
try
@@ -189,9 +173,6 @@ namespace DevourClient.Network
}
}
- ///
- /// Show message box
- ///
public static void ShowMessageBox(string message)
{
try
diff --git a/DevourClient/RadialMenuManager.cs b/DevourClient/RadialMenuManager.cs
new file mode 100644
index 0000000..9eda661
--- /dev/null
+++ b/DevourClient/RadialMenuManager.cs
@@ -0,0 +1,698 @@
+using System;
+using System.Collections.Generic;
+using MelonLoader;
+using UnityEngine;
+using DevourClient.Helpers;
+using DevourClient.Localization;
+using System.Globalization;
+
+namespace DevourClient
+{
+ // Manages the Z-key radial menu: building options, drawing the UI, and executing actions.
+ // Public static methods are called from the appropriate ClientMain lifecycle hooks.
+ internal static class RadialMenuManager
+ {
+ private static bool _active;
+ private static int _selectedIndex = -1;
+ private static readonly List _options = new List();
+ private static bool _cursorStateStored;
+ private static bool _prevCursorVisible;
+ private static CursorLockMode _prevCursorLockState;
+ private static bool _enabled = true; // Controls whether the radial menu is enabled
+
+ // Material used to draw radial arcs (GL immediate mode)
+ private static Material _radialMaterial;
+
+ // Public property to enable/disable the radial menu
+ public static bool Enabled
+ {
+ get => _enabled;
+ set => _enabled = value;
+ }
+
+ private enum RadialActionType
+ {
+ None,
+ SpawnItem,
+ TeleportBase,
+ TeleportFixedPoint
+ }
+
+ private class RadialOption
+ {
+ public string Label = string.Empty;
+ public RadialActionType ActionType = RadialActionType.None;
+ public string Payload = string.Empty;
+ }
+
+ // Called from Update: handles input, builds / closes the radial menu and executes actions.
+ public static void HandleUpdate()
+ {
+ if (!_enabled || !Player.IsInGameOrLobby())
+ return;
+
+ if (Input.GetKeyDown(KeyCode.Z))
+ {
+ BuildForCurrentScene();
+ }
+
+ if (Input.GetKeyUp(KeyCode.Z) && _active)
+ {
+ if (_selectedIndex >= 0 && _selectedIndex < _options.Count)
+ {
+ ExecuteOption(_options[_selectedIndex]);
+ }
+
+ _active = false;
+ _selectedIndex = -1;
+ _options.Clear();
+
+ RestoreCursorState();
+ }
+ }
+
+ // Called from OnGUI: draws the radial menu if it is active.
+ public static void HandleOnGUI()
+ {
+ if (!_enabled || !_active || !Player.IsInGameOrLobby())
+ return;
+
+ Draw();
+ }
+
+ private static void BuildForCurrentScene()
+ {
+ _options.Clear();
+ _selectedIndex = -1;
+
+ string sceneName = Helpers.Map.GetActiveScene();
+ if (string.IsNullOrEmpty(sceneName) || sceneName == "Menu")
+ {
+ _active = false;
+ return;
+ }
+
+ _options.Add(new RadialOption
+ {
+ Label = MultiLanguageSystem.Translate("First aid"),
+ ActionType = RadialActionType.SpawnItem,
+ Payload = "SurvivalFirstAid"
+ });
+
+ _options.Add(new RadialOption
+ {
+ Label = MultiLanguageSystem.Translate("Battery"),
+ ActionType = RadialActionType.SpawnItem,
+ Payload = "SurvivalBattery"
+ });
+
+ _options.Add(new RadialOption
+ {
+ Label = MultiLanguageSystem.Translate("TP Base"),
+ ActionType = RadialActionType.TeleportBase,
+ Payload = string.Empty
+ });
+
+ switch (sceneName)
+ {
+ case "Devour":
+ case "Anna":
+ _options.Add(new RadialOption
+ {
+ Label = MultiLanguageSystem.Translate("TP Altar"),
+ ActionType = RadialActionType.TeleportFixedPoint,
+ Payload = "8.57 0.01 -65.19"
+ });
+
+ _options.Add(new RadialOption
+ {
+ Label = MultiLanguageSystem.Translate("Hay"),
+ ActionType = RadialActionType.SpawnItem,
+ Payload = "SurvivalHay"
+ });
+ _options.Add(new RadialOption
+ {
+ Label = MultiLanguageSystem.Translate("Gasoline"),
+ ActionType = RadialActionType.SpawnItem,
+ Payload = "SurvivalGasoline"
+ });
+ break;
+
+ case "Molly":
+ _options.Add(new RadialOption
+ {
+ Label = MultiLanguageSystem.Translate("TP Altar"),
+ ActionType = RadialActionType.TeleportFixedPoint,
+ Payload = "18.12 -8.80 21.06"
+ });
+
+ _options.Add(new RadialOption
+ {
+ Label = MultiLanguageSystem.Translate("Fuse"),
+ ActionType = RadialActionType.SpawnItem,
+ Payload = "SurvivalFuse"
+ });
+ _options.Add(new RadialOption
+ {
+ Label = MultiLanguageSystem.Translate("RottenFood"),
+ ActionType = RadialActionType.SpawnItem,
+ Payload = "SurvivalRottenFood"
+ });
+ break;
+
+ case "Inn":
+ _options.Add(new RadialOption
+ {
+ Label = MultiLanguageSystem.Translate("TP Fountain"),
+ ActionType = RadialActionType.TeleportFixedPoint,
+ Payload = "-3.43 0.06 24.31"
+ });
+
+ _options.Add(new RadialOption
+ {
+ Label = MultiLanguageSystem.Translate("Bleach"),
+ ActionType = RadialActionType.SpawnItem,
+ Payload = "SurvivalBleach"
+ });
+ break;
+
+ case "Town":
+ _options.Add(new RadialOption
+ {
+ Label = MultiLanguageSystem.Translate("TP Altar"),
+ ActionType = RadialActionType.TeleportFixedPoint,
+ Payload = "-56.88 7.17 -34.51"
+ });
+ _options.Add(new RadialOption
+ {
+ Label = MultiLanguageSystem.Translate("Matchbox"),
+ ActionType = RadialActionType.SpawnItem,
+ Payload = "Matchbox-3"
+ });
+ _options.Add(new RadialOption
+ {
+ Label = MultiLanguageSystem.Translate("Gasoline"),
+ ActionType = RadialActionType.SpawnItem,
+ Payload = "SurvivalGasoline"
+ });
+
+ break;
+
+ case "Slaughterhouse":
+ _options.Add(new RadialOption
+ {
+ Label = MultiLanguageSystem.Translate("TP Altar"),
+ ActionType = RadialActionType.TeleportFixedPoint,
+ Payload = "26.68 4.01 -9.27"
+ });
+
+ _options.Add(new RadialOption
+ {
+ Label = MultiLanguageSystem.Translate("Bone"),
+ ActionType = RadialActionType.SpawnItem,
+ Payload = "SurvivalBone"
+ });
+ _options.Add(new RadialOption
+ {
+ Label = MultiLanguageSystem.Translate("Gasoline"),
+ ActionType = RadialActionType.SpawnItem,
+ Payload = "SurvivalGasoline"
+ });
+ break;
+
+ case "Manor":
+ _options.Add(new RadialOption
+ {
+ Label = MultiLanguageSystem.Translate("TP Basin"),
+ ActionType = RadialActionType.TeleportFixedPoint,
+ Payload = "38.93 -4.62 -3.86"
+ });
+
+ _options.Add(new RadialOption
+ {
+ Label = MultiLanguageSystem.Translate("Bleach"),
+ ActionType = RadialActionType.SpawnItem,
+ Payload = "SurvivalBleach"
+ });
+ _options.Add(new RadialOption
+ {
+ Label = MultiLanguageSystem.Translate("Cake"),
+ ActionType = RadialActionType.SpawnItem,
+ Payload = "SurvivalCake"
+ });
+ _options.Add(new RadialOption
+ {
+ Label = MultiLanguageSystem.Translate("Spade"),
+ ActionType = RadialActionType.SpawnItem,
+ Payload = "SurvivalSpade"
+ });
+ break;
+
+ case "Carnival":
+ _options.Add(new RadialOption
+ {
+ Label = MultiLanguageSystem.Translate("TP Altar"),
+ ActionType = RadialActionType.TeleportFixedPoint,
+ Payload = "-114.65 4.07 -4.12"
+ });
+
+ _options.Add(new RadialOption
+ {
+ Label = MultiLanguageSystem.Translate("Coin"),
+ ActionType = RadialActionType.SpawnItem,
+ Payload = "SurvivalCoin"
+ });
+ _options.Add(new RadialOption
+ {
+ Label = MultiLanguageSystem.Translate("MusicBox"),
+ ActionType = RadialActionType.SpawnItem,
+ Payload = "MusicBox-Idle"
+ });
+ _options.Add(new RadialOption
+ {
+ Label = MultiLanguageSystem.Translate("DollHead"),
+ ActionType = RadialActionType.SpawnItem,
+ Payload = "SurvivalDollHead"
+ });
+ break;
+ }
+
+ if (_options.Count == 0)
+ {
+ _active = false;
+ return;
+ }
+
+ _active = true;
+ HideCursorForRadial();
+ }
+
+ private static void Draw()
+ {
+ Event e = Event.current;
+ if (e == null)
+ return;
+
+ bool isRepaint = e.type == EventType.Repaint;
+
+ float centerX = Screen.width / 2f;
+ float centerY = Screen.height / 2f;
+ Vector2 center = new Vector2(centerX, centerY);
+
+ float radiusOuter = 140f;
+ float radiusInner = 40f;
+
+ Vector2 mouse = e.mousePosition;
+ Vector2 dir = mouse - center;
+ float dist = dir.magnitude;
+
+ _selectedIndex = -1;
+
+ if (dist >= radiusInner && dist <= radiusOuter && _options.Count > 0)
+ {
+ // Normalize angles: convert GUI coordinates (y down) to math coordinates (y up)
+ // and treat "up" as 0° increasing clockwise.
+ Vector2 upDir = new Vector2(dir.x, -dir.y);
+ float mathAngle = Mathf.Atan2(upDir.y, upDir.x); // [-PI, PI], 0 is on the right, counterclockwise is positive
+
+ float logicalAngle = (Mathf.PI / 2f) - mathAngle;
+ if (logicalAngle < 0f)
+ {
+ logicalAngle += Mathf.PI * 2f;
+ }
+
+ float logicalSectorAngle = (Mathf.PI * 2f) / _options.Count;
+ int index = Mathf.Clamp(Mathf.FloorToInt(logicalAngle / logicalSectorAngle), 0, _options.Count - 1);
+ _selectedIndex = index;
+ }
+
+ int count = _options.Count;
+ if (count == 0)
+ return;
+
+ if (isRepaint)
+ {
+ EnsureRadialMaterial();
+ DrawFilledCircle(center, radiusOuter + 6f, new Color(0f, 0f, 0f, 0.55f));
+ }
+
+ // Sector layout and label radius
+ float logicalAnglePerSector = (Mathf.PI * 2f) / count;
+ float radiusFactor;
+ if (count <= 6)
+ radiusFactor = 0.55f;
+ else if (count == 7)
+ radiusFactor = 0.48f;
+ else if (count <= 8)
+ radiusFactor = 0.5f;
+ else
+ radiusFactor = 0.45f;
+ float labelRadius = radiusInner + (radiusOuter - radiusInner) * radiusFactor;
+
+ if (isRepaint)
+ {
+ for (int i = 0; i < count; i++)
+ {
+ float logicalStart = logicalAnglePerSector * i;
+ float logicalEnd = logicalAnglePerSector * (i + 1);
+
+ float displayStart = (Mathf.PI / 2f) - logicalStart;
+ float displayEnd = (Mathf.PI / 2f) - logicalEnd;
+
+ Color sectorColor = (i == _selectedIndex)
+ ? new Color(0.15f, 0.7f, 0.3f, 0.8f)
+ : new Color(0.1f, 0.1f, 0.1f, 0.7f);
+
+ DrawFilledSector(center, radiusInner, radiusOuter, displayStart, displayEnd, sectorColor);
+ }
+ }
+
+ GUIStyle labelStyle = new GUIStyle(GUI.skin.label)
+ {
+ alignment = TextAnchor.MiddleCenter,
+ normal = { textColor = Color.white },
+ fontSize = (count <= 6) ? 14 : (count <= 8 ? 12 : 10),
+ wordWrap = true
+ };
+
+ for (int i = 0; i < count; i++)
+ {
+ float logicalMid = logicalAnglePerSector * (i + 0.5f);
+ float displayMid = (Mathf.PI / 2f) - logicalMid;
+
+ float lx = centerX + Mathf.Cos(displayMid) * labelRadius;
+ float ly = centerY - Mathf.Sin(displayMid) * labelRadius;
+
+ float arcLength = logicalAnglePerSector * labelRadius;
+ float arcFactor;
+ float minWidth;
+ float maxWidth;
+
+ if (count <= 6)
+ {
+ arcFactor = 0.8f;
+ minWidth = 60f;
+ maxWidth = 120f;
+ }
+ else if (count == 7)
+ {
+ arcFactor = 0.6f;
+ minWidth = 45f;
+ maxWidth = 75f;
+ }
+ else if (count <= 8)
+ {
+ arcFactor = 0.65f;
+ minWidth = 45f;
+ maxWidth = 80f;
+ }
+ else
+ {
+ arcFactor = 0.55f;
+ minWidth = 40f;
+ maxWidth = 70f;
+ }
+
+ float baseWidth = arcLength * arcFactor;
+
+ float labelWidth = Mathf.Clamp(baseWidth, minWidth, maxWidth);
+ float labelHeight = 32f;
+
+ Rect labelRect = new Rect(lx - labelWidth / 2f, ly - labelHeight / 2f, labelWidth, labelHeight);
+ GUI.Label(labelRect, _options[i].Label, labelStyle);
+ }
+ }
+
+ private static void EnsureRadialMaterial()
+ {
+ if (_radialMaterial != null)
+ return;
+
+ Shader shader = Shader.Find("Hidden/Internal-Colored");
+ if (shader == null)
+ return;
+
+ _radialMaterial = new Material(shader)
+ {
+ hideFlags = HideFlags.HideAndDontSave
+ };
+ _radialMaterial.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
+ _radialMaterial.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
+ _radialMaterial.SetInt("_Cull", (int)UnityEngine.Rendering.CullMode.Off);
+ _radialMaterial.SetInt("_ZWrite", 0);
+ }
+
+ private static void DrawFilledCircle(Vector2 center, float radius, Color color)
+ {
+ if (_radialMaterial == null)
+ return;
+
+ _radialMaterial.SetPass(0);
+ GL.PushMatrix();
+ GL.LoadPixelMatrix(0, Screen.width, Screen.height, 0);
+
+ GL.Begin(GL.TRIANGLES);
+ GL.Color(color);
+
+ const int steps = 64;
+ for (int i = 0; i < steps; i++)
+ {
+ float t0 = (float)i / steps;
+ float t1 = (float)(i + 1) / steps;
+
+ float ang0 = t0 * Mathf.PI * 2f;
+ float ang1 = t1 * Mathf.PI * 2f;
+
+ float x0 = center.x + Mathf.Cos(ang0) * radius;
+ float y0 = center.y - Mathf.Sin(ang0) * radius;
+ float x1 = center.x + Mathf.Cos(ang1) * radius;
+ float y1 = center.y - Mathf.Sin(ang1) * radius;
+
+ GL.Vertex3(center.x, center.y, 0f);
+ GL.Vertex3(x0, y0, 0f);
+ GL.Vertex3(x1, y1, 0f);
+ }
+
+ GL.End();
+ GL.PopMatrix();
+ }
+
+ private static void DrawFilledSector(Vector2 center, float innerRadius, float outerRadius,
+ float startAngle, float endAngle, Color color)
+ {
+ if (_radialMaterial == null)
+ return;
+
+ _radialMaterial.SetPass(0);
+ GL.PushMatrix();
+ GL.LoadPixelMatrix(0, Screen.width, Screen.height, 0);
+
+ GL.Begin(GL.TRIANGLES);
+ GL.Color(color);
+
+ int steps = Mathf.Max(8, Mathf.CeilToInt(Mathf.Abs(endAngle - startAngle) / (Mathf.PI / 24f)));
+ float delta = (endAngle - startAngle) / steps;
+
+ for (int i = 0; i < steps; i++)
+ {
+ float a0 = startAngle + delta * i;
+ float a1 = startAngle + delta * (i + 1);
+
+ Vector2 o0 = new Vector2(
+ center.x + Mathf.Cos(a0) * outerRadius,
+ center.y - Mathf.Sin(a0) * outerRadius);
+ Vector2 o1 = new Vector2(
+ center.x + Mathf.Cos(a1) * outerRadius,
+ center.y - Mathf.Sin(a1) * outerRadius);
+
+ Vector2 i0 = new Vector2(
+ center.x + Mathf.Cos(a0) * innerRadius,
+ center.y - Mathf.Sin(a0) * innerRadius);
+ Vector2 i1 = new Vector2(
+ center.x + Mathf.Cos(a1) * innerRadius,
+ center.y - Mathf.Sin(a1) * innerRadius);
+
+ GL.Vertex3(o0.x, o0.y, 0f);
+ GL.Vertex3(o1.x, o1.y, 0f);
+ GL.Vertex3(i1.x, i1.y, 0f);
+
+ GL.Vertex3(o0.x, o0.y, 0f);
+ GL.Vertex3(i1.x, i1.y, 0f);
+ GL.Vertex3(i0.x, i0.y, 0f);
+ }
+
+ GL.End();
+ GL.PopMatrix();
+ }
+
+ private static void ExecuteOption(RadialOption option)
+ {
+ if (option == null || option.ActionType == RadialActionType.None)
+ return;
+
+ try
+ {
+ switch (option.ActionType)
+ {
+ case RadialActionType.SpawnItem:
+ if (string.IsNullOrEmpty(option.Payload))
+ return;
+
+ ClientMain_HandleItemCarry(option.Payload);
+ break;
+
+ case RadialActionType.TeleportBase:
+ TeleportToBase();
+ break;
+
+ case RadialActionType.TeleportFixedPoint:
+ TeleportToFixedPoint(option.Payload);
+ break;
+ }
+ }
+ catch (Exception ex)
+ {
+ MelonLogger.Error($"Radial option execution failed: {ex.Message}");
+ }
+ }
+
+ private static void HideCursorForRadial()
+ {
+ if (!_cursorStateStored)
+ {
+ _prevCursorVisible = Cursor.visible;
+ _prevCursorLockState = Cursor.lockState;
+ _cursorStateStored = true;
+ }
+
+ Cursor.lockState = CursorLockMode.None;
+ Cursor.visible = true;
+ }
+
+ private static void RestoreCursorState()
+ {
+ if (!_cursorStateStored)
+ return;
+
+ Cursor.lockState = _prevCursorLockState;
+ Cursor.visible = _prevCursorVisible;
+ _cursorStateStored = false;
+ }
+
+ // Calls ClientMain.HandleItemCarry via reflection to avoid tight coupling,
+ // and falls back to Hacks.Misc.CarryObject if that fails.
+ private static void ClientMain_HandleItemCarry(string payload)
+ {
+ try
+ {
+ var type = typeof(ClientMain);
+ var method = type.GetMethod("HandleItemCarry",
+ System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
+ if (method != null)
+ {
+ method.Invoke(null, new object[] { payload });
+ return;
+ }
+ }
+ catch
+ {
+ // ignore and fallback
+ }
+
+ Hacks.Misc.CarryObject(payload);
+ }
+
+ // Teleports the player to a fixed world position.
+ // Payload format: "x y z" using '.' as decimal separator.
+ private static void TeleportToFixedPoint(string payload)
+ {
+ if (string.IsNullOrWhiteSpace(payload))
+ return;
+
+ try
+ {
+ string[] parts = payload.Split(new[] { ' ', '\t', ',' }, StringSplitOptions.RemoveEmptyEntries);
+ if (parts.Length < 3)
+ return;
+
+ float x = float.Parse(parts[0], CultureInfo.InvariantCulture);
+ float y = float.Parse(parts[1], CultureInfo.InvariantCulture);
+ float z = float.Parse(parts[2], CultureInfo.InvariantCulture);
+
+ Il2Cpp.NolanBehaviour nb = Player.GetPlayer();
+ if (nb == null)
+ return;
+
+ Vector3 target = new Vector3(x, y, z);
+ nb.TeleportTo(target, Quaternion.identity);
+ }
+ catch (Exception ex)
+ {
+ MelonLogger.Error($"TeleportToFixedPoint failed: {ex.Message}");
+ }
+ }
+
+ // Teleports the player to the map-specific base coordinates (former RecallToBase logic).
+ private static void TeleportToBase()
+ {
+ try
+ {
+ Il2Cpp.NolanBehaviour nb = Player.GetPlayer();
+ if (nb == null)
+ {
+ MelonLogger.Warning("Player not found!");
+ return;
+ }
+
+ string sceneName = Helpers.Map.GetActiveScene();
+ Vector3 targetPos = Vector3.zero;
+ string mapName = "";
+
+ switch (sceneName)
+ {
+ case "Devour":
+ case "Anna": // Farmhouse
+ targetPos = new Vector3(5.03f, 4.20f, -50.02f);
+ mapName = "Farm";
+ break;
+ case "Molly": // Asylum
+ targetPos = new Vector3(17.52f, 1.38f, 7.04f);
+ mapName = "Asylum";
+ break;
+ case "Inn":
+ targetPos = new Vector3(3.53f, 0.84f, 2.47f);
+ mapName = "Inn";
+ break;
+ case "Town":
+ targetPos = new Vector3(-63.51f, 10.88f, -12.32f);
+ mapName = "Town";
+ break;
+ case "Slaughterhouse":
+ targetPos = new Vector3(6.09f, 0.70f, -17.58f);
+ mapName = "Slaughterhouse";
+ break;
+ case "Manor":
+ targetPos = new Vector3(3.67f, 1.32f, -23.34f);
+ mapName = "Manor";
+ break;
+ case "Carnival":
+ targetPos = new Vector3(-91.46f, 8.13f, -24.51f);
+ mapName = "Carnival";
+ break;
+ default:
+ MelonLogger.Warning($"Teleport not available for scene: {sceneName}");
+ return;
+ }
+
+ nb.locomotion.SetPosition(targetPos, false);
+ MelonLogger.Msg($"Teleported to {mapName} coordinates: X:{targetPos.x:F2} Y:{targetPos.y:F2} Z:{targetPos.z:F2}");
+ }
+ catch (Exception ex)
+ {
+ MelonLogger.Error($"Failed to teleport to base: {ex.Message}");
+ }
+ }
+ }
+}
+
+
diff --git a/README.md b/README.md
index a09d529..5fa30b1 100644
--- a/README.md
+++ b/README.md
@@ -103,9 +103,9 @@ If you want to modify and develop the code, please follow the [Building from sou
4、运行devour → 如果安装成功,你会看到一个windows窗口进行各类安装提示后,自动进入游戏。点击insert键即可打开和关闭devourclient窗口
-**注意:**有些电脑在安装melonloader之后,会出现fatal error的提示,这个我目前并没有碰到过。但是出现这个提示的主要原因,基本是melonloader安装过程中,提取到devour根目录的melonloader文件夹里的文件出现了问题,比较简单的解决办法就是(1)在别人的同系统同位宽(x86,x32)的电脑里拷贝出来他的melonloader文件夹,然后直接粘贴到自己的电脑里。(2)将melonloader文件夹完全删除,然后重装。(3)在直到游戏完全运行,菜单正常工作之前,保持VPN线路通畅。
+注意:有些电脑在安装melonloader之后,会出现fatal error的提示,这个我目前并没有碰到过。但是出现这个提示的主要原因,基本是melonloader安装过程中,提取到devour根目录的melonloader文件夹里的文件出现了问题,比较简单的解决办法就是(1)在别人的同系统同位宽(x86,x32)的电脑里拷贝出来他的melonloader文件夹,然后直接粘贴到自己的电脑里。(2)将melonloader文件夹完全删除,然后重装。(3)在直到游戏完全运行,菜单正常工作之前,保持VPN线路通畅。
-**注意:**如果在加载时提示 “0 mod”,请检查你的dll文件是否正常,是否已经将dll文件放置到devour的“mods”文件夹中。
+注意:如果在加载时提示 “0 mod”,请检查你的dll文件是否正常,是否已经将dll文件放置到devour的“mods”文件夹中。
如果你想要对代码进行修改和开发,请按照下面的 [building from source](#building-from-source) 的步骤,逐步进行