diff --git a/Config/Localization.csv b/Config/Localization.csv index f99f592..0fd9cc8 100644 --- a/Config/Localization.csv +++ b/Config/Localization.csv @@ -261,6 +261,7 @@ necroWolfBagWaypoint,items,Item,,,,Wolf bag,,Wolfstasche,Bolsa del lobo,Sac du l necroZombieBagWindowTitle,items,Item,,,,Zombie bag,,Zombietasche,Bolsa del zombi,Sac du zombie,Borsa dello zombi,ゾンビの袋,좀비 가방,Torba zombie,Bolsa do zumbi,Сумка зомби,Zombi çantası,僵尸的包,殭屍的包 necroZombieBagWaypoint,items,Item,,,,Zombie bag,,Zombietasche,Bolsa del zombi,Sac du zombie,Borsa dello zombi,ゾンビの袋,좀비 가방,Torba zombie,Bolsa do zumbi,Сумка зомби,Zombi çantası,僵尸的包,殭屍的包 necroPossessHintZombieBag,items,Item,,,,"Tab - bag, E at a container, loot bag or item - into the bag",,"Tab - Tasche, E an Behälter, Beutel oder Gegenstand - in die Tasche","Tab: bolsa, E en un contenedor, saco o objeto: a la bolsa","Tab : sac, E sur un conteneur, un sac ou un objet : dans le sac","Tab - borsa, E su contenitore, sacca o oggetto - nella borsa","Tab: 袋、コンテナ・袋・アイテムにE: 袋へ","Tab - 가방, 상자·자루·물건에 E - 가방으로","Tab - torba, E na pojemniku, worku lub przedmiocie - do torby","Tab - bolsa, E em contêiner, saco ou item - para a bolsa","Tab - сумка, E на ящик, мешок или предмет - в сумку","Tab - çanta, kaba, torbaya veya eşyaya E - çantaya","Tab - 包,对容器、袋子或物品按E - 放入包","Tab - 包,對容器、袋子或物品按E - 放入包" +necroPossessHintDoor,items,Item,,,,"E at a door or switch - use it",,"E an Tür oder Schalter - benutzen","E en una puerta o interruptor: usar","E sur une porte ou un interrupteur : utiliser","E su porta o interruttore - usare","ドアやスイッチにE: 使う","문이나 스위치에 E - 사용","E na drzwiach lub przełączniku - użyj","E em porta ou interruptor - usar","E на дверь или выключатель - открыть, включить","Kapıya veya şaltere E - kullan","对门或开关按E - 使用","對門或開關按E - 使用" necroZombieBagTook,items,Item,,,,"Zombie bag ({1}/{2}): {0}",,"Zombietasche ({1}/{2}): {0}","Bolsa del zombi ({1}/{2}): {0}","Sac du zombie ({1}/{2}) : {0}","Borsa dello zombi ({1}/{2}): {0}","ゾンビの袋({1}/{2}):{0}","좀비 가방 ({1}/{2}): {0}","Torba zombie ({1}/{2}): {0}","Bolsa do zumbi ({1}/{2}): {0}","Сумка зомби ({1}/{2}): {0}","Zombi çantası ({1}/{2}): {0}","僵尸的背包({1}/{2}):{0}","殭屍的背包({1}/{2}):{0}" necroZombieBagFull,items,Item,,,,"The zombie bag is full ({1}/{2}): {0}",,"Die Zombietasche ist voll ({1}/{2}): {0}","La bolsa del zombi está llena ({1}/{2}): {0}","Le sac du zombie est plein ({1}/{2}) : {0}","La borsa dello zombi è piena ({1}/{2}): {0}","ゾンビの袋がいっぱい({1}/{2}):{0}","좀비 가방이 가득 찼습니다 ({1}/{2}): {0}","Torba zombie jest pełna ({1}/{2}): {0}","A bolsa do zumbi está cheia ({1}/{2}): {0}","Сумка зомби полна ({1}/{2}): {0}","Zombi çantası dolu ({1}/{2}): {0}","僵尸的背包已满({1}/{2}):{0}","殭屍的背包已滿({1}/{2}):{0}" necroZombieBagShow,items,Item,,,,"Zombie bag ({1}/{2}): {0}",,"Zombietasche ({1}/{2}): {0}","Bolsa del zombi ({1}/{2}): {0}","Sac du zombie ({1}/{2}) : {0}","Borsa dello zombi ({1}/{2}): {0}","ゾンビの袋({1}/{2}):{0}","좀비 가방 ({1}/{2}): {0}","Torba zombie ({1}/{2}): {0}","Bolsa do zumbi ({1}/{2}): {0}","Сумка зомби ({1}/{2}): {0}","Zombi çantası ({1}/{2}): {0}","僵尸的背包({1}/{2}):{0}","殭屍的背包({1}/{2}):{0}" diff --git a/HarmonySrc/Possession.cs b/HarmonySrc/Possession.cs index 302846c..5561418 100644 --- a/HarmonySrc/Possession.cs +++ b/HarmonySrc/Possession.cs @@ -595,6 +595,12 @@ namespace NecromancerTome // кнопка геймпада (тест 03.10: «подрыва нету»). detonate = input.Activate.WasPressed || input.PermanentActions.Activate.WasPressed; } + // E на дверь или выключатель - как у персонажа (указание 13.10: одержимым управляет ГГ - «ему хватает ума не + // ломать дверь, которую можно открыть»); у волка и крысы - нет. Прицел не на двери - E как раньше. + if (detonate && !IsPet && UseDoorOrSwitch(world, z)) + { + detonate = false; + } // Только гуманоиды обычной комплекции (указание 13.10, FpArms.Allows) - у остальных ~/ё ничего не делает. if (input != null && !gui && FpArms.Allows(z) && (input.CameraChange.WasPressed || input.QuickMenu.WasPressed || input.PermanentActions.QuickMenu.WasPressed)) @@ -1592,6 +1598,10 @@ namespace NecromancerTome { text += ", " + Localization.Get("necroPossessHintZombieBag"); } + if (!IsPet) + { + text += ", " + Localization.Get("necroPossessHintDoor"); // двери и выключатели (13.10) + } if (Flying) { text += ", " + Localization.Get("necroPossessHintFly"); @@ -2145,6 +2155,73 @@ namespace NecromancerTome _flyZoomHeld = false; } + /// Команды блока, которые одержимый выполняет по E (как первая доступная команда у персонажа): двери + /// (TEFeatureDoor - open/close), выключатели и лампы (light), рычаги квестов (activate). Без take, lock, edit, + /// trigger. Запертую чужую дверь не откроет - замок проверяет сама дверь. + static readonly string[] UseCommands = { "open", "close", "light", "activate" }; + public const float UseReach = 3f; + + static bool UseDoorOrSwitch(World _world, EntityAlive _z) + { + Transform cam = _player?.cameraTransform; + if (cam == null || _world == null) + { + return false; + } + int n = Physics.RaycastNonAlloc(cam.position, cam.forward, _aimHits, 50f, -5, QueryTriggerInteraction.Ignore); + Transform self = _z.transform; + float best = float.MaxValue; + RaycastHit hit = default; + for (int i = 0; i < n; i++) + { + RaycastHit h = _aimHits[i]; + if (h.distance >= best || h.transform == self || h.transform.IsChildOf(self)) + { + continue; + } + best = h.distance; + hit = h; + } + if (best == float.MaxValue) + { + return false; + } + Vector3 at = hit.point + Origin.position; + if ((at - _z.getHeadPosition()).sqrMagnitude > UseReach * UseReach) + { + return false; + } + Vector3i pos = World.worldToBlockPos(at + cam.forward * 0.05f); + BlockValue bv = _world.GetBlock(pos); + if (bv.isair) + { + pos = World.worldToBlockPos(at - cam.forward * 0.05f); + bv = _world.GetBlock(pos); + } + if (bv.ischild) + { + pos += bv.parent; + bv = _world.GetBlock(pos); + } + Block b = bv.Block; + if (bv.isair || b == null) + { + return false; + } + BlockActivationCommand[] cmds = b.GetBlockActivationCommands(_world, bv, pos, _player); + for (int i = 0; cmds != null && i < cmds.Length; i++) + { + if (!cmds[i].enabled || System.Array.IndexOf(UseCommands, cmds[i].text) < 0) + { + continue; + } + b.OnBlockActivated(cmds[i].text, _world, pos, bv, _player); + Debug.Log("[NecromancerTome] Possession: " + _z.EntityName + " - " + cmds[i].text + " " + b.GetBlockName() + " " + pos); + return true; + } + return false; + } + /// Миг удара рук от первого лица (FpArms): зомби бьёт сразу - его удар начат и сразу «дошёл до точки /// удара» (ForceImpact в EntityAlive.IsAttackImpact, задержка луча ItemActionMelee снята). Урон, дальность, /// цель - его, взгляд - на прицел (MeleeAim). diff --git a/NecromancerHarmony.dll b/NecromancerHarmony.dll index 469330b..98b9fac 100644 Binary files a/NecromancerHarmony.dll and b/NecromancerHarmony.dll differ diff --git a/NecromancerHarmony.pdb b/NecromancerHarmony.pdb index 100bcc7..2e1ed0a 100644 Binary files a/NecromancerHarmony.pdb and b/NecromancerHarmony.pdb differ