Волк: сумка видна в окне рюкзака при обыске, 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 ячейки); у тела - выгрузить сумку в рюкзак;
|
||||
// иначе - «багажник», окно сумки (указание 09.10).
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -233,7 +233,10 @@ namespace NecromancerTome
|
||||
{
|
||||
return;
|
||||
}
|
||||
__instance.xui.playerUI.windowManager.Close("backpack");
|
||||
if (!Taking)
|
||||
{
|
||||
__instance.xui.playerUI.windowManager.Close("backpack"); // у волка рюкзак показывает его сумку (WolfBagBackpack)
|
||||
}
|
||||
LockSlots(__instance.lootWindow, true);
|
||||
}
|
||||
}
|
||||
@@ -337,7 +340,10 @@ namespace NecromancerTome
|
||||
{
|
||||
return;
|
||||
}
|
||||
__instance.xui.playerUI.windowManager.Close("backpack");
|
||||
if (!Taking)
|
||||
{
|
||||
__instance.xui.playerUI.windowManager.Close("backpack");
|
||||
}
|
||||
LockSlots(__instance.containerWindow, true);
|
||||
}
|
||||
}
|
||||
|
||||
+175
-1
@@ -16,7 +16,11 @@ namespace NecromancerTome
|
||||
/// - «багажник» (указание 09.10: «почти как у пространственного хранилища»): E не на контейнер и не у тела -
|
||||
/// окно сумки, то же ванильное окно, что у браслета (XUiC_BagStorageWindowGroup, шаблон roboticDrone), но
|
||||
/// без рюкзака персонажа: внутри перекладывать, вытащить за окно - выбросить у волка (Patch_GetDropPosition);
|
||||
/// - мешки с зомби волк лутает так же, как ящики (RatLoot, TakeFrom(EntityLootContainer)).
|
||||
/// - мешки с зомби волк лутает так же, как ящики (RatLoot, TakeFrom(EntityLootContainer));
|
||||
/// - тест 10.10: «волк - это ещё одно пространственное хранилище: берёт игрок, но положить может только в эти
|
||||
/// 3 ячейки» - при обыске рядом с ящиком окно рюкзака показывает сумку волка (WolfBagBackpack: первые 3
|
||||
/// ячейки, остальные скрыты, ячейки заперты - перекладка щелчком по ящику), а E на предмет на земле
|
||||
/// кладёт его в сумку (TryPickup).
|
||||
///
|
||||
/// ХРАНЕНИЕ. Сумку сущности игра не сохраняет (Entity.bag нет в Entity.Write), поэтому она своя.
|
||||
/// Упаковка - та же, что у пространственного хранилища (SpatialVaultPersistence.BuildPayload/ParsePayload,
|
||||
@@ -35,6 +39,11 @@ namespace NecromancerTome
|
||||
public const string WaypointIcon = "ui_game_symbol_backpack";
|
||||
/// <summary>Открыто окно сумки («багажник»).</summary>
|
||||
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 string _dir;
|
||||
|
||||
@@ -77,6 +86,7 @@ namespace NecromancerTome
|
||||
|
||||
static void Save()
|
||||
{
|
||||
Version++;
|
||||
try
|
||||
{
|
||||
if (_bag == null || _bag.IsEmpty())
|
||||
@@ -181,6 +191,52 @@ namespace NecromancerTome
|
||||
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>
|
||||
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))]
|
||||
public static class Patch_EntityAlive_OnEntityDeath_WolfBag
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user