namespace Aeshnidae.AwakenedRewards;
///
/// /ar-lootlog: what actually went into each corpse a player made - for chasing "no kit
/// ever drops" (2026-09-27: Tom watched Lucy McJuicy's kills for a long time and saw no
/// healing or stamina kit, while ACE's corpse simulator made one on about 1 corpse in 12
/// from the same profile). Off by default and not kept across a reload: it is a
/// diagnostic, one log line per corpse while on.
///
/// Read after ACE's Creature.GenerateTreasure has filled the corpse: the treasure profile,
/// every item in the corpse by name, and what the roll handed back that did not end up in
/// the corpse (a full corpse drops the rest).
///
[HarmonyPatch]
public static class LootLog
{
public static bool On;
/// Only kills by this player (name, case-insensitive); empty = every player's.
public static string Player = "";
public static int Logged, WithKit, RolledKit;
/// What the loot roll handed back for the corpse being made on this thread.
[ThreadStatic] private static List? _rolled;
[HarmonyPostfix]
[HarmonyPatch(typeof(LootGenerationFactory), nameof(LootGenerationFactory.CreateRandomLootObjects), new[] { typeof(TreasureDeath) })]
public static void PostRoll(List __result)
{
if (On)
_rolled = __result?.ToList();
}
[HarmonyPostfix]
[HarmonyPatch(typeof(Creature), "GenerateTreasure")]
public static void PostGenerateTreasure(Creature __instance, DamageHistoryInfo killer, Corpse corpse, List __result)
{
if (!On)
return;
try
{
var who = killer?.TryGetAttacker() as Player ?? (killer?.PetOwner is not null && killer.PetOwner.TryGetTarget(out var owner) ? owner : null);
if (who is null)
return;
if (Player.Length > 0 && !who.Name.Equals(Player, StringComparison.OrdinalIgnoreCase))
return;
var items = corpse?.Inventory.Values.ToList() ?? new List();
var kit = items.Any(i => i.WeenieType == WeenieType.Healer);
var rolled = _rolled ?? new List();
_rolled = null;
var rolledKit = rolled.Any(i => i.WeenieType == WeenieType.Healer);
Logged++;
if (kit) WithKit++;
if (rolledKit) RolledKit++;
// Rolled but not in the corpse: ACE's TryAddToInventory failed and the item was lost.
var lost = rolled.Where(r => !items.Any(i => ReferenceEquals(i, r) || i.Guid == r.Guid)).Select(r => r.Name).ToList();
var profile = __instance.DeathTreasureType;
var names = items.Count == 0 ? "empty" : string.Join(", ", items.Select(i => $"{i.Name}{(i.WeenieType == WeenieType.Healer ? " [KIT]" : "")}"));
var dropped = __result is { Count: > 0 } ? $"; not in the corpse: {string.Join(", ", __result.Select(i => i.Name))}" : "";
ModManager.Log($"[{Mod.Name}] lootlog: {who.Name} killed {__instance.Name} (profile {profile?.ToString() ?? "none"}) in {__instance.CurrentLandblock?.Id.Landblock:X4}: " +
$"{items.Count} item(s): {names}{dropped}{(lost.Count > 0 ? $"; ROLLED BUT LOST: {string.Join(", ", lost)}" : "")} " +
$"[corpses {Logged}, kit rolled {RolledKit}, kit in corpse {WithKit}]");
}
catch (Exception ex)
{
ModManager.Log($"[{Mod.Name}] lootlog failed: {ex.Message}", ModManager.LogLevel.Warn);
}
}
}