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); } } }