Волк: сумка видна в окне рюкзака при обыске, E подбирает предметы с земли в сумку
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
eaf06e1cd9
commit
654b888d15
@@ -667,7 +667,8 @@ namespace NecromancerTome
|
|||||||
// E: на контейнер или мешок с зомби - лутать в сумку (3 ячейки); у тела - выгрузить сумку в рюкзак;
|
// E: на контейнер или мешок с зомби - лутать в сумку (3 ячейки); у тела - выгрузить сумку в рюкзак;
|
||||||
// иначе - «багажник», окно сумки (указание 09.10).
|
// иначе - «багажник», окно сумки (указание 09.10).
|
||||||
bool looted = RatLoot.Tick(world, _player, z, detonate, true);
|
bool looted = RatLoot.Tick(world, _player, z, detonate, true);
|
||||||
if (detonate && !looted && !RatLoot.Viewing && !WolfBag.TryUnload(_player, z))
|
// E на предмет на земле - в сумку (тест 10.10: «не могу подбирать выброшенные предметы»).
|
||||||
|
if (detonate && !looted && !RatLoot.Viewing && !WolfBag.TryPickup(world, _player, z) && !WolfBag.TryUnload(_player, z))
|
||||||
{
|
{
|
||||||
WolfBag.OpenWindow(_player, z);
|
WolfBag.OpenWindow(_player, z);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -233,7 +233,10 @@ namespace NecromancerTome
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
__instance.xui.playerUI.windowManager.Close("backpack");
|
if (!Taking)
|
||||||
|
{
|
||||||
|
__instance.xui.playerUI.windowManager.Close("backpack"); // у волка рюкзак показывает его сумку (WolfBagBackpack)
|
||||||
|
}
|
||||||
LockSlots(__instance.lootWindow, true);
|
LockSlots(__instance.lootWindow, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -337,7 +340,10 @@ namespace NecromancerTome
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
__instance.xui.playerUI.windowManager.Close("backpack");
|
if (!Taking)
|
||||||
|
{
|
||||||
|
__instance.xui.playerUI.windowManager.Close("backpack");
|
||||||
|
}
|
||||||
LockSlots(__instance.containerWindow, true);
|
LockSlots(__instance.containerWindow, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+175
-1
@@ -16,7 +16,11 @@ namespace NecromancerTome
|
|||||||
/// - «багажник» (указание 09.10: «почти как у пространственного хранилища»): E не на контейнер и не у тела -
|
/// - «багажник» (указание 09.10: «почти как у пространственного хранилища»): E не на контейнер и не у тела -
|
||||||
/// окно сумки, то же ванильное окно, что у браслета (XUiC_BagStorageWindowGroup, шаблон roboticDrone), но
|
/// окно сумки, то же ванильное окно, что у браслета (XUiC_BagStorageWindowGroup, шаблон roboticDrone), но
|
||||||
/// без рюкзака персонажа: внутри перекладывать, вытащить за окно - выбросить у волка (Patch_GetDropPosition);
|
/// без рюкзака персонажа: внутри перекладывать, вытащить за окно - выбросить у волка (Patch_GetDropPosition);
|
||||||
/// - мешки с зомби волк лутает так же, как ящики (RatLoot, TakeFrom(EntityLootContainer)).
|
/// - мешки с зомби волк лутает так же, как ящики (RatLoot, TakeFrom(EntityLootContainer));
|
||||||
|
/// - тест 10.10: «волк - это ещё одно пространственное хранилище: берёт игрок, но положить может только в эти
|
||||||
|
/// 3 ячейки» - при обыске рядом с ящиком окно рюкзака показывает сумку волка (WolfBagBackpack: первые 3
|
||||||
|
/// ячейки, остальные скрыты, ячейки заперты - перекладка щелчком по ящику), а E на предмет на земле
|
||||||
|
/// кладёт его в сумку (TryPickup).
|
||||||
///
|
///
|
||||||
/// ХРАНЕНИЕ. Сумку сущности игра не сохраняет (Entity.bag нет в Entity.Write), поэтому она своя.
|
/// ХРАНЕНИЕ. Сумку сущности игра не сохраняет (Entity.bag нет в Entity.Write), поэтому она своя.
|
||||||
/// Упаковка - та же, что у пространственного хранилища (SpatialVaultPersistence.BuildPayload/ParsePayload,
|
/// Упаковка - та же, что у пространственного хранилища (SpatialVaultPersistence.BuildPayload/ParsePayload,
|
||||||
@@ -35,6 +39,11 @@ namespace NecromancerTome
|
|||||||
public const string WaypointIcon = "ui_game_symbol_backpack";
|
public const string WaypointIcon = "ui_game_symbol_backpack";
|
||||||
/// <summary>Открыто окно сумки («багажник»).</summary>
|
/// <summary>Открыто окно сумки («багажник»).</summary>
|
||||||
public static bool WindowOpen;
|
public static bool WindowOpen;
|
||||||
|
/// <summary>Счётчик изменений сумки - окно рюкзака перерисовывает её по нему.</summary>
|
||||||
|
public static int Version;
|
||||||
|
/// <summary>Предмет на земле - не дальше стольких метров от волка и градусов от луча камеры.</summary>
|
||||||
|
const float PickupReach = 2.5f;
|
||||||
|
const float PickupAimDeg = 25f;
|
||||||
static Bag _bag;
|
static Bag _bag;
|
||||||
static string _dir;
|
static string _dir;
|
||||||
|
|
||||||
@@ -77,6 +86,7 @@ namespace NecromancerTome
|
|||||||
|
|
||||||
static void Save()
|
static void Save()
|
||||||
{
|
{
|
||||||
|
Version++;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (_bag == null || _bag.IsEmpty())
|
if (_bag == null || _bag.IsEmpty())
|
||||||
@@ -181,6 +191,52 @@ namespace NecromancerTome
|
|||||||
return rest.count > 0 ? rest : ItemStack.Empty.Clone();
|
return rest.count > 0 ? rest : ItemStack.Empty.Clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>E на предмет, лежащий на земле, - в сумку (как игрок подбирает: что не влезло, остаётся лежать).
|
||||||
|
/// True - предмет перед волком был (взят или «сумка полна»).</summary>
|
||||||
|
public static bool TryPickup(World _world, EntityPlayerLocal _player, EntityAlive _wolf)
|
||||||
|
{
|
||||||
|
Transform cam = _player.cameraTransform;
|
||||||
|
if (cam == null || _world.IsRemote())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Vector3 from = cam.position + Origin.position;
|
||||||
|
EntityItem best = null;
|
||||||
|
float bestDeg = PickupAimDeg;
|
||||||
|
for (int i = 0; i < _world.Entities.list.Count; i++)
|
||||||
|
{
|
||||||
|
if (!(_world.Entities.list[i] is EntityItem it) || it.IsDead() || it.IsMarkedForUnload() || it.itemStack == null ||
|
||||||
|
it.itemStack.IsEmpty() || !it.CanCollect() || (it.position - _wolf.position).sqrMagnitude > PickupReach * PickupReach)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
float deg = Vector3.Angle(cam.forward, it.position - from);
|
||||||
|
if (deg < bestDeg)
|
||||||
|
{
|
||||||
|
bestDeg = deg;
|
||||||
|
best = it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (best == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ItemStack rest = Take(best.itemStack);
|
||||||
|
if (rest == null)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (rest.IsEmpty())
|
||||||
|
{
|
||||||
|
_world.RemoveEntity(best.entityId, EnumRemoveEntityReason.Killed);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
best.itemStack.count = rest.count;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>«Взять всё» - по ячейкам, пока есть место.</summary>
|
/// <summary>«Взять всё» - по ячейкам, пока есть место.</summary>
|
||||||
public static void TakeAll(TEFeatureStorage _te)
|
public static void TakeAll(TEFeatureStorage _te)
|
||||||
{
|
{
|
||||||
@@ -423,6 +479,124 @@ namespace NecromancerTome
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Окно рюкзака при обыске волком показывает сумку волка (указание 10.10). Рюкзак персонажа при этом
|
||||||
|
/// не читается и не пишется: UpdateBackend пропущен - в сейв игрока сумка не попадёт.</summary>
|
||||||
|
public static class WolfBagBackpack
|
||||||
|
{
|
||||||
|
public static bool On => RatLoot.Viewing && RatLoot.Taking && Possession.Active;
|
||||||
|
static int _seen = -1;
|
||||||
|
static readonly List<XUiC_ItemStack> _hidden = new List<XUiC_ItemStack>();
|
||||||
|
|
||||||
|
public static ItemStack[] Slots(int _n)
|
||||||
|
{
|
||||||
|
ItemStack[] a = new ItemStack[_n];
|
||||||
|
ItemStack[] b = WolfBag.Get().ItemGrid.items;
|
||||||
|
for (int i = 0; i < _n; i++)
|
||||||
|
{
|
||||||
|
a[i] = i < b.Length && b[i] != null ? b[i].Clone() : ItemStack.Empty.Clone();
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Tick(XUiC_Backpack _bp)
|
||||||
|
{
|
||||||
|
if (_seen != WolfBag.Version || _hidden.Count == 0)
|
||||||
|
{
|
||||||
|
_seen = WolfBag.Version;
|
||||||
|
_bp.RefreshBackpackSlots();
|
||||||
|
}
|
||||||
|
XUiC_ItemStack[] c = _bp.itemControllers;
|
||||||
|
for (int i = 0; c != null && i < c.Length; i++)
|
||||||
|
{
|
||||||
|
c[i].IsLocked = true;
|
||||||
|
if (i >= WolfBag.Slots && c[i].ViewComponent.IsVisible)
|
||||||
|
{
|
||||||
|
c[i].ViewComponent.IsVisible = false;
|
||||||
|
_hidden.Add(c[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Обыск закончен: ячейки рюкзака снова видны и отперты, рюкзак - снова свой.</summary>
|
||||||
|
public static void Unlock(XUiC_Backpack _bp)
|
||||||
|
{
|
||||||
|
foreach (XUiC_ItemStack s in _hidden)
|
||||||
|
{
|
||||||
|
if (s != null)
|
||||||
|
{
|
||||||
|
s.ViewComponent.IsVisible = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool was = _hidden.Count > 0 || _seen != -1;
|
||||||
|
_hidden.Clear();
|
||||||
|
_seen = -1;
|
||||||
|
if (_bp?.itemControllers == null || !was)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
foreach (XUiC_ItemStack s in _bp.itemControllers)
|
||||||
|
{
|
||||||
|
if (s != null)
|
||||||
|
{
|
||||||
|
s.IsLocked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_bp.RefreshBackpackSlots();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(XUiC_Backpack), nameof(XUiC_Backpack.GetSlots))]
|
||||||
|
public static class Patch_Backpack_GetSlots_WolfBag
|
||||||
|
{
|
||||||
|
public static bool Prefix(XUiC_Backpack __instance, ref ItemStack[] __result)
|
||||||
|
{
|
||||||
|
if (!WolfBagBackpack.On)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
__result = WolfBagBackpack.Slots(__instance.itemControllers?.Length ?? WolfBag.Slots);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(XUiC_Backpack), nameof(XUiC_Backpack.UpdateBackend))]
|
||||||
|
public static class Patch_Backpack_UpdateBackend_WolfBag
|
||||||
|
{
|
||||||
|
public static bool Prefix()
|
||||||
|
{
|
||||||
|
return !WolfBagBackpack.On;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(XUiC_Backpack), nameof(XUiC_Backpack.Update))]
|
||||||
|
public static class Patch_Backpack_Update_WolfBag
|
||||||
|
{
|
||||||
|
static bool _was;
|
||||||
|
|
||||||
|
public static void Postfix(XUiC_Backpack __instance)
|
||||||
|
{
|
||||||
|
bool on = WolfBagBackpack.On;
|
||||||
|
if (on)
|
||||||
|
{
|
||||||
|
WolfBagBackpack.Tick(__instance);
|
||||||
|
}
|
||||||
|
else if (_was)
|
||||||
|
{
|
||||||
|
WolfBagBackpack.Unlock(__instance);
|
||||||
|
}
|
||||||
|
_was = on;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(XUiC_Backpack), nameof(XUiC_Backpack.OnClose))]
|
||||||
|
public static class Patch_Backpack_OnClose_WolfBag
|
||||||
|
{
|
||||||
|
public static void Postfix(XUiC_Backpack __instance)
|
||||||
|
{
|
||||||
|
WolfBagBackpack.Unlock(__instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[HarmonyPatch(typeof(EntityAlive), nameof(EntityAlive.OnEntityDeath))]
|
[HarmonyPatch(typeof(EntityAlive), nameof(EntityAlive.OnEntityDeath))]
|
||||||
public static class Patch_EntityAlive_OnEntityDeath_WolfBag
|
public static class Patch_EntityAlive_OnEntityDeath_WolfBag
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user