WolfBag.Target - текущая сумка (зомби, если он с сумкой, иначе волка): обыск, подбор, окно рюкзака при обыске и подсказки общие. Тексты «Сумка зомби» и подсказка E - 13 языков. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
167 lines
6.8 KiB
C#
167 lines
6.8 KiB
C#
using System.Collections.Generic;
|
||
using System.IO;
|
||
using UnityEngine;
|
||
|
||
namespace NecromancerTome
|
||
{
|
||
/// <summary>
|
||
/// Сумка одержимого зомби (указание 13.10: «всем одержимым зомби с видом от первого лица сумку и возможность вызывать
|
||
/// её по Tab»). Решения пользователя 13.10:
|
||
/// - своя, одна на всех зомби, число ячеек - по виду зомби (SlotsFor), пока у всех 2;
|
||
/// - при выходе из одержимости зомби сбрасывает рюкзаком всё, что было в сумке (и на поясе - когда в поясе
|
||
/// появятся предметы);
|
||
/// - гибель одержимого - мешок на месте и метка на карте, как у сумки волка.
|
||
/// Лут (указание 13.10: «раз у них E свободно, подключай лутание») - как у волка: E на ящик или мешок - обыск с
|
||
/// переносом в сумку, E на предмет на земле - подобрать (WolfBag.Target - сумка зомби, пока она есть).
|
||
/// Только зомби из списка вида от первого лица (FpArms.Allows), не питомцы. Окно - то же, что у сумки волка
|
||
/// (XUiC_BagStorageWindowGroup, без рюкзака персонажа), Tab в зомби открывает его вместо рюкзака.
|
||
///
|
||
/// ХРАНЕНИЕ. Сумка живёт одно вселение, но пишется в отдельный файл сейва при каждом изменении (как сумка волка,
|
||
/// сейв игрока не трогается): вылет посреди вселения вещи не теряет - при следующем вселении то, что осталось в
|
||
/// файле, выпадает мешком у тела.
|
||
/// </summary>
|
||
public static class ZombieBag
|
||
{
|
||
const string FileName = "NecromancerTome_zombiebag.bin";
|
||
public const int DefaultSlots = 2;
|
||
/// <summary>Метка выпавшей сумки - ключ локализации (снимается вместе с меткой сумки волка, когда мешок исчез).</summary>
|
||
public const string WaypointName = "necroZombieBagWaypoint";
|
||
public static bool WindowOpen;
|
||
static Bag _bag;
|
||
|
||
static string FilePath => Path.Combine(GameIO.GetSaveGameDir(), FileName);
|
||
|
||
public static bool Active => _bag != null;
|
||
public static Bag Current => _bag;
|
||
|
||
/// <summary>Записать после лута (WolfBag.SaveTarget).</summary>
|
||
public static void SaveNow() => Save();
|
||
|
||
/// <summary>У кого сумка: зомби с видом от первого лица, не питомцы.</summary>
|
||
public static bool Has(EntityAlive _z, bool _pet) => !_pet && FpArms.Allows(_z);
|
||
|
||
/// <summary>Ячеек у этого вида зомби (указание: «каким-то добавим, каким-то наоборот») - пока у всех DefaultSlots.</summary>
|
||
public static int SlotsFor(EntityAlive _z) => DefaultSlots;
|
||
|
||
/// <summary>Вселение началось: то, что осталось в файле после вылета, - мешком у тела; новая пустая сумка.</summary>
|
||
public static void Begin(EntityPlayerLocal _body, EntityAlive _z)
|
||
{
|
||
try
|
||
{
|
||
if (File.Exists(FilePath))
|
||
{
|
||
Bag old = SpatialVaultPersistence.ParsePayload(File.ReadAllBytes(FilePath));
|
||
List<ItemStack> left = Items(old);
|
||
if (left.Count > 0 && _body != null)
|
||
{
|
||
WolfBag.DropSack(_body.position + _body.GetForwardVector() * 0.8f, left);
|
||
Debug.Log("[NecromancerTome] ZombieBag: в файле осталась сумка прошлого вселения - мешком у тела (" + left.Count + ")");
|
||
}
|
||
File.Delete(FilePath);
|
||
}
|
||
}
|
||
catch (System.Exception e)
|
||
{
|
||
Debug.LogWarning("[NecromancerTome] ZombieBag: файл сумки не прочитан (" + e.Message + ") - оставлен как есть");
|
||
}
|
||
_bag = new Bag(new Vector2i(SlotsFor(_z), 1), XUiC_ItemStack.StackLocationTypes.LootContainer, null);
|
||
Debug.Log("[NecromancerTome] ZombieBag: сумка " + _z.EntityName + " - ячеек " + _bag.SlotCount);
|
||
}
|
||
|
||
/// <summary>Вселение кончилось: всё из сумки - мешком на месте зомби; погиб - ещё и метка на карте.</summary>
|
||
public static void End(EntityAlive _z)
|
||
{
|
||
if (_bag == null)
|
||
{
|
||
return;
|
||
}
|
||
CloseWindow();
|
||
List<ItemStack> items = Items(_bag);
|
||
_bag = null;
|
||
Save();
|
||
if (items.Count == 0 || _z == null)
|
||
{
|
||
return;
|
||
}
|
||
bool died = _z.IsDead();
|
||
WolfBag.DropSack(_z.position, items);
|
||
if (died)
|
||
{
|
||
WolfBag.AddWaypoint(_z.position, WaypointName);
|
||
}
|
||
Debug.Log("[NecromancerTome] ZombieBag: " + (died ? "одержимый погиб" : "выход из одержимости") + " - сумка мешком (" + items.Count + ")");
|
||
}
|
||
|
||
static List<ItemStack> Items(Bag _b)
|
||
{
|
||
List<ItemStack> items = new List<ItemStack>();
|
||
if (_b?.ItemGrid?.items == null)
|
||
{
|
||
return items;
|
||
}
|
||
foreach (ItemStack s in _b.ItemGrid.items)
|
||
{
|
||
if (s != null && !s.IsEmpty())
|
||
{
|
||
items.Add(s.Clone());
|
||
}
|
||
}
|
||
return items;
|
||
}
|
||
|
||
static void Save()
|
||
{
|
||
try
|
||
{
|
||
if (_bag == null || _bag.IsEmpty())
|
||
{
|
||
if (File.Exists(FilePath))
|
||
{
|
||
File.Delete(FilePath);
|
||
}
|
||
return;
|
||
}
|
||
File.WriteAllBytes(FilePath, SpatialVaultPersistence.BuildPayload(_bag));
|
||
}
|
||
catch (System.Exception e)
|
||
{
|
||
Debug.LogWarning("[NecromancerTome] ZombieBag: сумка не записана - " + e.Message);
|
||
}
|
||
}
|
||
|
||
/// <summary>Tab в зомби - окно сумки, как «багажник» волка (WolfBag.OpenWindow).</summary>
|
||
public static void OpenWindow(EntityPlayerLocal _player, EntityAlive _z)
|
||
{
|
||
LocalPlayerUI ui = LocalPlayerUI.GetUIForPlayer(_player);
|
||
if (ui == null || _bag == null)
|
||
{
|
||
return;
|
||
}
|
||
WindowOpen = true;
|
||
XUiC_BagStorageWindowGroup.Open(ui.xui, _z, _bag, LootContainer.GetLootContainer("roboticDrone"),
|
||
Localization.Get("necroZombieBagWindowTitle"), Save, () =>
|
||
{
|
||
WindowOpen = false;
|
||
Save();
|
||
});
|
||
Debug.Log("[NecromancerTome] ZombieBag: окно сумки");
|
||
}
|
||
|
||
public static void CloseWindow()
|
||
{
|
||
if (WindowOpen)
|
||
{
|
||
LocalPlayerUI.GetUIForPrimaryPlayer()?.windowManager.CloseAllOpenModalWindows();
|
||
WindowOpen = false;
|
||
}
|
||
}
|
||
|
||
/// <summary>Выход из мира - забыть (файл остаётся: при следующем вселении выпадет мешком у тела).</summary>
|
||
public static void Forget()
|
||
{
|
||
_bag = null;
|
||
WindowOpen = false;
|
||
}
|
||
}
|
||
}
|