Author: JFFK

0

LibArmorInsulation (2.7.5)

# LibArmorInsulation**Version 2.7.5** ESO API 101049 101050 License: MIT*by @Kreksar5 and Claude.ai*> **AI-ASSISTED ADDON.** Large portions of this addon’s code (the costume/outfit> scanning commands, the resolver priority logic, and several data-table> structures) and its UESP-sourced costume/style insulation data were written> with Claude.ai, and **have not yet been independently validated in-game**> for correctness or performance. Material/insulation assignments carry an> explicit “ tag in `LibArmorInsulation_StyleData.lua`> where applicable `low`-confidence entries in particular are thematic> inferences, not verified facts, and are good candidates for manual> re-checking against UESP or in-game testing before being trusted as accurate.> This notice will be removed once the addon has seen real play-testing.A reusable ESO addon library that calculates a **staggered-tier thermal insulation score (-10 to 90, in steps of 10)** for the player based on their current visual appearance taking into account armor style, material composition, body-slot coverage, and flavor-text bonuses or penalties from the style database. The score mirrors ESO’s own visual-priority rules: polymorphs beat costumes, costumes beat outfits, outfits beat worn armor.—## Table of Contents1. (#installation)2. (#dependencies)3. (#insulation-model)4. (#visual-priority-cascade)5. (#public-api)6. (#slash-commands)7. (#settings-panel)8. (#adding–editing-style-data)9. (#eso-api-functions-used)10. (#design-notes–limitations)11. (#changelog)—## Installation1. Drop the `LibArmorInsulation` folder into `Elder Scrolls OnlineliveAddOns`.2. Ensure **LibAddonMenu-2.0 (v33+)** is also installed ((https://www.esoui.com/)).3. Enable the addon in the ESO Addon Manager.—## Dependencies| Library | Required | Notes ||—|—|—|| LibAddonMenu-2.0 ≥ 33 | **Yes** | Settings panel only. The calculation API works without LAM, but the settings panel will be unavailable. || LibStyleInfo | No | Not used. Its confirmed public API exposes style IDtoname lookups and light/medium/heavy weight flags, but not material composition, body-coverage percentage, or flavor text. || LibMotifCategories | No | Not used. Motif category data (crafted/overland/dungeon/etc.) does not map to thermal properties. |> **Why maintain an internal style database?**> Both evaluated libraries were ruled out because neither provides the material or coverage data needed for insulation math. LibArmorInsulation therefore ships its own hand-authored table keyed on `ITEM_STYLE_*` integer constants, which every ESO item carries natively.—## Insulation Model### ScaleAll values resolve to one of **eleven fixed tiers**, staggered in increments of 10 from **-10 to 90**:| Tier | Label | Meaning ||—|—|—|| -10 | Magically Cooled | Magically cooled equipment (e.g. refrigeration) || 0 | No Insulation | No insulation || 10 | Minimal | Underwear/swimwear || 20 | Light | Light silks, breathable thin fabrics, or minimal coverage || 30 | Coarse Light | Linens, coarser fabrics, or small amounts of leather with light coverage || 40 | Layered/Leather | Thick or many-layered fabrics, or majority-coverage leathers || 50 | Full Leather/Light Metal | Full coverage leathers, mild coverage metals, or full-coverage multi-layered thick fabrics || 60 | Heavy Leather/Fur | Full coverage heavy/thick leathers, mild coverage furs, or moderate coverage metals || 70 | Full Fur/Metal | Full coverage furs or full coverage metals || 80 | Heavy Fur/Metal | Full coverage heavy furs and/or metals || 90 | Magically Heated | Magically heated equipment |`-10` and `90` are reserved for entries explicitly flagged `magical = true` in the data tables (Flame Atronach, Ice Wraith, etc.). Every other entry is clamped to the mundane **080** range before being snapped to the nearest tier, so ordinary armor and clothing can never accidentally read as magically hot or cold.> **Why a tier ladder instead of a continuous score?** It’s a much better fit for anything that has to *display* insulation a UI can show one of 11 discrete states/icons instead of trying to render 101 shades of meaning. It’s also easier to reason about and balance by hand: every entry in the data tables is describable in one of eleven plain-English buckets rather than an arbitrary integer.### How an entry becomes a tierArmor styles and outfit style pieces keep their existing `baseMaterial` + `coverage` + `flavorBonus` authoring fields nothing in the data tables needed to be hand-rewritten for the tier system. The Calculator computes the same full-body reference score it always has, then **snaps** that score onto the nearest tier:“`raw = 0.90 styleCoverage materialCoeff SCALE_FACTOR + flavorBonustier = SnapToTier(raw, magical) — nearest of {-10,0,10,…,80,90} — clamped to first unless the entry has `magical = true““`SCALE_FACTOR = 55.556` anchors a full set of standard leather armor at coverage 1.0 to exactly tier 50.Costumes and polymorphs keep their existing hand-authored `totalInsulation` field, which is likewise snapped to the nearest tier at lookup time (again clamped to 080 unless `magical = true`).### Per-slot percentage adjustment (unless it’s a full costume)A style/outfit piece’s tier is its **full-body reference value**. Individual armor/outfit slots then contribute a **percentage** of that tier based on how much of the body they cover:“`slot_contribution = round(tier slotPercentage)total = sum(slot_contribution for every worn slot)“`Slot percentages now sum to exactly **1.00** across the 7 thermally-relevant slots (previously 0.90, compensated by `SCALE_FACTOR`), so a full matching set (every slot the same tier) reproduces that tier as the total. Missing slots count as bare skin (tier 0) for that percentage of the body small independent-rounding artifacts of a point or two are possible when summing per-slot contributions, but the total will never drift outside the -10..90 tier range.**Costumes and polymorphs are NOT slot-adjusted.** They represent the whole body at once, so their snapped tier *is* the total, unadjusted there’s no percentage to apply.### Slot coverage weights| Slot | Percentage ||—|—|| Chest | 33% || Legs | 28% || Head | 11% || Shoulders | 11% || Hands | 6% || Feet | 6% || Waist | 5% || Rings, Neck, Weapons | 0% |### Material coefficients| Material | Coefficient | Full-set reference (pre-snap) | Snapped tier ||—|—|—|—|| fur | 1.8 | 90 | 80 (mundane cap) || wool | 1.5 | 75 | 70 (tie rounds down) || heavy_leather | 1.3 | 65 | 60 (tie rounds down) || leather | 1.0 | 50 (baseline) | 50 || scale | 0.8 | 40 | 40 || runic | 0.8 | 40 | 40 || bone | 0.7 | 35 | 30 (tie rounds down) || cloth | 0.7 | 35 | 30 (tie rounds down) || chitin | 0.6 | 30 | 30 || hide | 0.6 | 30 | 30 || iron | 0.5 | 25 | 20 (tie rounds down) || steel | 0.5 | 25 | 20 (tie rounds down) || silk | 0.5 | 25 | 20 (tie rounds down) || linen | 0.4 | 20 | 20 || aetherial | 0.4 | 20 | 20 || daedric | 0.3 | 15 | 10 (tie rounds down) || crystal | 0.2 | 10 | 10 || none | 0.0 | 0 | 0 |Ties (raw score exactly halfway between two tiers, e.g. 75 between 70 and 80) round **down** to the lower tier `Calc.SnapToTier()` picks the first tier with the smallest difference while scanning the ladder ascending, so the lower of two equidistant tiers wins.”Full-set reference” assumes coverage 1.0 and no flavor bonus; per-style `coverage`/`flavorBonus` modifiers shift the raw score up or down before it’s snapped, so an individual style’s tier can land a step away from its base material’s own tier (e.g. Nord’s fur base plus its +8 flavor bonus and 1.1 coverage pushes it to the mundane ceiling of tier 80).### Costume & polymorph scoringCostumes and polymorphs bypass per-slot math entirely. They return a single snapped tier looked up from `CostumeInsulationById` (by collectible ID), then `CostumeInsulation` (by normalized lowercase name), then the appropriate default:| Fallback | Raw default | Snapped tier ||—|—|—|| `DEFAULT_COSTUME` | 50 | 50 || `DEFAULT_POLYMORPH` | 38 | 40 |**Costume lookup priority.** Order is: user override (already a tier used as-is) → `CostumeInsulationById` (by collectible ID) → `CostumeInsulation` (by name, manually curated see Changelog 2.5.0) → `sv.costumeCache` (populated by `/scancostumes`) → `DEFAULT_COSTUME`. Run `/scancostumes` to populate the cache with keyword-derived auto-ratings for anything not already in the manual tables.—## Visual Priority Cascade`GetTotalInsulation()` and `GetInsulationBreakdown()` mirror ESO’s own visual priority rules, evaluated top-to-bottom:1. **Polymorph** detected via `GetActiveCollectibleByType(COLLECTIBLE_CATEGORY_TYPE_COSTUME)` combined with keyword/ID matching against polymorph entries. Returns a flat body-wide score; slot math is skipped.2. **Costume** same detection mechanism. Returns a flat body-wide score; slot math is skipped.3. **Active Outfit** detected via `GetEquippedOutfitIndex()`. Slot insulation is calculated from the collectible ID on each `OUTFIT_SLOT_*` using `ZO_OUTFIT_MANAGER`. Only slots with a non-zero style override contribute; if *no* outfit slots are overridden, falls through to armor.4. **Worn Armor** calls `GetItemLink(BAG_WORN, equipSlot)` then `GetItemLinkItemStyle(itemLink)` for each thermally relevant `EQUIP_SLOT_*`. `GetItemLinkItemStyle` is used (not `GetItemStyle`) because it returns the correct visual style for all item origins crafted, dropped, set, and Crown Store items alike.5. **Naked** returns 0.—## Public API“`lua– Total insulation score, one of the 11 tiers for costume/polymorph;– a composite (-10..90) for armor/outfit made of per-slot tier contributionslocal total = LibArmorInsulation.GetTotalInsulation()– Full breakdown tablelocal info = LibArmorInsulation.GetInsulationBreakdown()– info.source : “polymorph” | “costume” | “outfit” | “armor” | “naked”– info.total : integer, -10..90– info.slots : table {– = {– styleId, — ITEM_STYLE_* (armor path) or nil– collectibleId, — collectible ID (outfit/costume path) or nil– insulation, — integer slot contribution (== tier for costume/polymorph)– tier, — the style/costume’s own full-body tier (-10..90)– slotPercentage, — 0-1 weight of this slot; nil for costume/polymorph– material, — string material key– flavorNote, — string human-readable note, or “”– armorFallback, — boolean: true if outfit slot fell back to worn armor– }– }– info.costumeId : number | nil (collectible ID of active costume/polymorph)– info.costumeName : string | nil (lower-cased collectible name)– Full-set reference tier for a given ITEM_STYLE_* id (respects overrides)– Returns one of {-10,0,10,20,30,40,50,60,70,80,90}local tier = LibArmorInsulation.GetInsulationForStyle(styleId)– Set a persisted insulation override one of the 11 tier values– idType : “style” → ITEM_STYLE_* integer (worn armor)– “outfit” → collectible ID (outfit slot piece)– “costume” → collectible ID (costume or polymorph)– value = nil removes the override. Non-tier numbers are snapped to the– nearest tier rather than rejected. In the Settings panel this is always a– dropdown, so it can’t drift off-tier.LibArmorInsulation.SetOverride(idType, id, value)– Remove all user overrides (does not clear the costume cache)LibArmorInsulation.ResetOverrides()“`### Constants“`luaLibArmorInsulation.VERSION — “2.7.0”LibArmorInsulation.ADDON_NAME — “LibArmorInsulation”“`### Saved variables schema (account-wide)“`luasv.overrides — { = tier integer (-10..90) }sv.costumeCache — { = { name, insulation, autoRated } } — Populated by /scancostumes; persists across sessions. — `insulation` here is a pre-snap raw value, snapped to the — nearest tier at lookup time.“`Override keys follow the pattern `_` (e.g. `style_42`, `outfit_1234567`, `costume_9876543`). This unified key space means a single `SetOverride` call handles all three entity types without ambiguity.—## Slash Commands### General| Command | Description ||—|—|| `/insulation` | Prints the current source, total score with its nearest tier label, and per-slot breakdown style/collectible ID, insulation contribution, tier, slot percentage, material to chat. || `/styleids` | Prints the `ITEM_STYLE_*` ID worn in each armor slot. Use this to find the ID to enter in the override editor when working with worn armor. |### Outfit commands| Command | Description ||—|—|| `/outfitids` | Prints the collectible ID and name applied to each slot of every styled outfit. Use this to find the collectible ID to enter as an `outfit_` override. || `/outfitactive` | Diagnostic probes free functions and `outfitManipulator` methods to determine whether each outfit is actively equipped versus merely stored. Run with an outfit equipped, then unequipped, and compare output. || `/scanoutfitstyles` | Walks every equipped slot across all unlocked outfits and, for any collectible ID not already in the hand-curated `OutfitStyles` table, keyword-rates it (by name, then description) and saves a guessed `{baseMaterial, coverage, flavorBonus}` to `sv.outfitStyleCache`. Run this after unlocking/equipping a new style page so it gets a value other than `OutfitStyles`. |### Costume & polymorph commands| Command | Description ||—|—|| `/costumeids` | Prints the collectible ID, display name, and current lookup method (user override / ID table / name table / DEFAULT_COSTUME) for the active costume or polymorph. Also prints the override key (`costume_`) to use in the settings panel. || `/scancostumes` | Walks every owned costume and polymorph in the Collections system and assigns a keyword-derived auto-rating to each (checking the name first, then the in-game description if the name has no match), saving the results in the costume cache (`sv.costumeCache`). Run this once and again after acquiring new costumes to ensure all owned costumes receive a meaningful score rather than the default. || `/clearcostumecache` | Removes all entries from `sv.costumeCache`. Re-run `/scancostumes` afterward to repopulate. |### Review commands| Command | Description ||—|—|| `/costumesneedreview` | Filters `sv.costumeCache` down to entries where the keyword scan found no match in either the name or description (sitting on the generic 50 default). Use this as a worklist for manual UESP-backed `CostumeInsulationById` entries instead of scrolling the full `/scancostumes` output. || `/outfitstylesneedreview` | Same as `/costumesneedreview`, but for `sv.outfitStyleCache` entries with no keyword match. Use as a worklist for manual `OutfitStyles` entries. |### Diagnostic commands| Command | Description ||—|—|| `/diagcollectibles` | Three-phase diagnostic that enumerates every collectible category and subcategory, identifies which one ESO marks as `COLLECTIBLE_CATEGORY_TYPE_COSTUME`, and reports the first reachable collectible per category. Run this and share the output if `/scancostumes` finds 0 costumes. |—## Settings PanelAccessible via **Addon Settings** in the ESO main menu.| Section | What it does ||—|—|| **Current Insulation** | Live breakdown of every slot’s contribution, tier, slot percentage, the source (outfit / armor / costume / polymorph), material, and any flavor note. Press **Refresh** to recalculate. || **Manual Overrides** | Pick a **Layer** (Costume/Polymorph, Outfit, or Armor) and, for Outfit/Armor, a **Slot** each selection does a fresh live lookup of that specific layer/slot (independent of what’s actually visually showing) and auto-fills Override Type/ID/Tier with it, or with a placeholder if nothing’s active there. Use **Refresh Preview** if you changed gear without touching the Layer/Slot dropdowns. Adjust the Tier if you like, then press **Apply Override**. Choosing “(no override)” removes an existing override. || **Active Overrides** | Lists all currently active overrides with their keys, tier values, and tier labels. || **Reset** | **Reset All Overrides** removes every override and reverts to database defaults. The costume cache is not affected. |> **Tip:** Use `/styleids` to find worn armor style IDs, `/outfitids` for outfit collectible IDs, and `/costumeids` for the active costume’s collectible ID before entering values in the override editor.—## Adding / Editing Style DataAll style data lives in `LibArmorInsulation_StyleData.lua`.### Armor styles (`LibArmorInsulationData.Styles`)Keys are `ITEM_STYLE_*` integer constants. Full list: “`lua = { baseMaterial = “leather”, — string key from MaterialCoefficient table coverage = 1.0, — style-level coverage modifier flavorBonus = 0, — flat integer bonus/penalty (can be negative) flavorNote = “”, — human-readable reason shown in settings & /insulation},“`Any style not in the table falls back to “ (leather, coverage 1.0, no bonus → score 50).### Outfit styles (`LibArmorInsulationData.OutfitStyles`)Keys are **collectible IDs** (Collections system integers), not `ITEM_STYLE_*` values. The two number spaces are unrelated. Use `/outfitids` to find collectible IDs.“`lua = { baseMaterial = “leather”, coverage = 1.0, flavorBonus = 0, flavorNote = “”,},“`Falls back to “ (leather, coverage 0.9).### Costume & polymorph entries (`LibArmorInsulationData.CostumeInsulationById` and `CostumeInsulation`)`CostumeInsulationById` is keyed by collectible ID (preferred); `CostumeInsulation` is keyed by lowercase display name (legacy fallback). Both use flat `totalInsulation` values.“`lua = { totalInsulation = 72, flavorNote = “Heavy bear-fur costume” },– or by name: = { totalInsulation = 30, flavorNote = “Thin ceremonial cloth” },“`Special keys “ (50) and “ (38) are the last-resort fallbacks.—## ESO API Functions Used| Function | Source | Purpose ||—|—|—|| `GetActiveCollectibleByType(type)` | ESO | Detect active costume / polymorph || `GetCollectibleName(id)` | ESO | Resolve collectible display name for data lookup || `GetCollectibleId(catIndex, subIndex, index)` | ESO | Iterate collectibles for costume scanning || `GetCollectibleInfo(id)` | ESO | Read unlock state during `/scancostumes` || `GetNumCollectibleCategories()` | ESO | Enumerate categories in `/diagcollectibles` || `GetCollectibleCategoryInfo(catIndex)` | ESO | Get category name in `/diagcollectibles` || `GetEquippedOutfitIndex()` | ESO | Detect whether an outfit is actively worn (confirmed in-game) || `GetNumUnlockedOutfits()` | ESO | Count unlocked outfits (takes **no** arguments) || `GetOutfitName(outfitIndex)` | ESO | Outfit display name for `/outfitids` || `ZO_OUTFIT_MANAGER:GetOutfitManipulator(actorCategory, outfitIndex)` | ESO | Access outfit slot data (actorCategory is required) || `outfitManipulator:GetSlotManipulator(OUTFIT_SLOT_*)` | ESO | Access individual outfit slots || `slotManipulator:GetCurrentCollectibleId()` | ESO | Collectible ID on a given outfit slot || `GetItemLink(bagId, slotIndex, linkStyle)` | ESO | Item link string for a worn equipment slot || `GetItemLinkItemStyle(itemLink)` | ESO | Visual style ID for any item regardless of origin || `BAG_WORN` | ESO | Constant the equipped item bag || `EQUIP_SLOT_*` | ESO | Equipment slot constants || `OUTFIT_SLOT_*` | ESO | Outfit slot constants || `COLLECTIBLE_CATEGORY_TYPE_COSTUME` | ESO | Collectible category constant || `ZO_SavedVars:NewAccountWide(…)` | ESO | Account-wide saved variables || `EVENT_MANAGER:RegisterForEvent(…)` | ESO | Addon load event || `CHAT_SYSTEM:AddMessage(…)` | ESO | Chat output || `SLASH_COMMANDS` | ESO | Slash command registration || `LibAddonMenu2:RegisterAddonPanel(…)` | LAM | Settings panel registration || `LibAddonMenu2:RegisterOptionControls(…)` | LAM | Settings controls |> **`GetItemLinkItemStyle` vs `GetItemStyle`:** `GetItemStyle()` only returns non-zero for player-crafted items; every dropped, set, or Crown Store piece returns `ITEM_STYLE_NONE` (0). `GetItemLinkItemStyle(itemLink)` returns the correct visual style for all item origins and is the correct choice here.>> **`GetNumUnlockedOutfits()`:** Takes no arguments. A `GameplayActorCategory` parameter does not exist on this function. `GetNumOutfits()` is not a real ESO API function and will crash with “function expected instead of nil”.>> **`GetEquippedOutfitIndex()`:** The correct gate for the outfit path. Confirmed working in-game; returns the 1-based index of the worn outfit, or nil if none.—## Design Notes & Limitations**No per-item flavor text scraping.** ESO does not provide a Lua API to read raw item flavor text at runtime (the tooltip system renders it as formatted strings, not structured data). The `flavorBonus` values in the style database are therefore authored by hand based on in-game style descriptions and motif book lore.**Item set names are ignored.** The library uses only the base `ITEM_STYLE_*` of each piece, not the set it belongs to. Set bonuses are mechanical gameplay systems unrelated to visual insulation.**Outfit “no override” slots fall through.** If a player has an outfit active but has not overridden every slot, only overridden slots contribute from the outfit source. If *no* outfit slots are overridden, the library falls through to worn armor styles entirely.**Costume vs. outfit visual conflict.** If a player has both a costume collectible active and an outfit applied, the costume wins visually in-game (costumes always take priority). LibArmorInsulation mirrors this by detecting costumes before outfits.**Polymorphs override costumes.** A polymorph replaces the entire character model. LibArmorInsulation checks for polymorphs before costumes, consistent with ESO’s in-game visual priority.**Outfit collectible IDs ≠ ITEM_STYLE_* IDs.** Outfit slots yield Collections-system collectible IDs, which are an entirely separate number space from `ITEM_STYLE_*` integers. The library maintains separate lookup tables (`OutfitStyles` and `Styles`) for this reason, and the override key prefix (`outfit_` vs `style_`) distinguishes them in saved variables.**Costume cache is opt-in.** The `sv.costumeCache` table is only populated when you run `/scancostumes`. Until then, unrecognized costumes fall back to `DEFAULT_COSTUME` (50). Cache entries persist across sessions.**Saved variables version 4.** The upgrade path from v3 preserves existing overrides and `costumeCache`, and adds the missing `outfitStyleCache` table. The upgrade path from v2 preserves overrides and adds both cache tables. Saves from v1 are reset to defaults to avoid schema conflicts.—## Changelog### 2.7.5- **Fixed the settings panel’s author/version fields**, which were still the literal placeholder text `”YourName”` and a hardcoded `”1.0.0″` never actually updated even after the `## Author` manifest field itself was corrected. The panel now reads `author = “@Kreksar5 and Claude.ai”` and `version = LibArmorInsulation.VERSION`, and the library’s internal `ADDON_VERSION` constant (previously stale at `”2.7.0″`) is kept in sync with the manifest `## Version` going forward.### 2.7.4- **Promoted 4 costumes and 11 outfit styles from verified player overrides** into the hard-coded data tables (`CostumeInsulationById` and `OutfitStyles`), so these no longer rely on a per-account manual override or auto-rated cache guess: – `CostumeInsulationById` gained 4 entries (collectible IDs 12717, 1101, 12719, 286) with their confirmed `totalInsulation` values, each superseding a previous auto-rated cache guess. – `OutfitStyles` gained 11 entries (collectible IDs 4804, 4798, 4800, 9746, 7195, 8786, 11819, 11818, 11820, 11851, 5309). The final tier for each is confirmed correct (set manually by a player after observing the outfit in-game), but since this table stores `baseMaterial`/`coverage`/ `flavorBonus` rather than a direct tier, those fields were chosen only as the minimal combination that reproduces the confirmed tier they are **not** an independent material assessment, and the collectibles’ actual names/appearances haven’t been looked up yet. Flagged accordingly in each entry’s `flavorNote`.### 2.7.3- **Standardized the author credit** to `@Kreksar5 and Claude.ai` in the `## Author` manifest field and this README’s byline, and named Claude.ai specifically (rather than generic “AI assistance”) in the manifest description and the AI-assistance disclosure above, matching the crediting convention used across this addon’s companion libraries.### 2.7.2- **Corrected the `## Author` manifest field**, which was still the literal placeholder text “YourName” left over from the manifest template never actually filled in. Fixed to the real author.### 2.7.1- **Full API audit against the official ESOUI API 101050 documentation.** Every function call, method call, and constant referenced across the library was cross-checked against the API doc and, where the doc didn’t cover it (manager singletons, third-party libraries), against the live ESOUI source. No invalid or deprecated API usage found `ZO_OUTFIT_MANAGER` and its `GetOutfitManipulator`/`GetSlotManipulator`/`GetCurrentCollectibleId` chain, and the `LibAddonMenu`/`LibSavedVars` calls, are all legitimate and correctly used. No code changes required.### 2.7.0- **Override editor redesigned around explicit Layer/Slot dropdowns.** Replaced the auto-detected “currently active item” list (and the 2.6.3 background poll that tried to keep it in sync) with two small, permanently static dropdowns: **Layer** (Costume/Polymorph, Outfit, Armor) and **Slot** (Head/Shoulders/Chest/Hands/Waist/Legs/Feet, disabled for Costume/Polymorph since that’s whole-body). Picking either does a FRESH live lookup at that exact moment via three new independent Calculator functions `Calc.ResolveCostumeOrPolymorph()`, `Calc.ResolveOutfitSlot()`, `Calc.ResolveArmorSlot()` each of which reads live game state directly and completely ignores ESO’s usual visual precedence. This means you can now inspect (and override) your Armor style on a slot even while a costume is actively displayed instead, or check what your Outfit has set for a slot regardless of what’s currently showing. If a layer/slot has nothing active (e.g. Costume picked while no costume is worn, or an empty armor slot), a placeholder tier and an explanatory note are shown instead of leaving the fields blank. A **Refresh Preview** button re-runs the same live lookup for whenever gear changes without touching either dropdown.- **Root-cause bug fix: Settings panel re-registration was silently a no-op.** The options table powering the whole Settings panel was declared as `local optionsTable = { …, func = function() … optionsTable … end, … }`. In Lua, a local variable’s scope begins only AFTER its declaration statement finishes, so any closure written INSIDE that table constructor which refers to `optionsTable` which is exactly what the Refresh/Apply Override/Reset buttons did to push a rebuilt panel back to LibAddonMenu actually resolved to a global of that name (`nil`), not the local table being built. Every one of those buttons had therefore been calling `LAM:RegisterOptionControls(Settings.panelId, nil)` this whole time. This is almost certainly the real reason the Settings panel never seemed to refresh, going back to before the tier-system rewrite. Fixed by forward-declaring `local optionsTable` on its own line before assigning the table to it, which is the standard Lua idiom for self-referencing structures; verified with a minimal isolated reproduction before and after the fix, and with an end-to-end test through the actual button handlers.### 2.6.3- **Background auto-refresh for the “currently active item” dropdown.** Previously the list only reflected equipped gear/costume/outfit at the moment the addon loaded, or whenever Refresh/Apply Override/Reset was pressed changing costume or outfit mid-session left it stale until one of those was clicked. Added a lightweight poll (`EVENT_MANAGER:RegisterForUpdate`, every 2 seconds) that compares a cheap fingerprint of “what’s currently resolving” (source + costume/polymorph ID + each slot’s collectible/style ID) against the last-seen one, and only pushes a rebuilt options table back to LibAddonMenu when something actually changed. This deliberately avoids hooking any specific ESO gear/costume-changed event, since there’s no single confirmed event that reliably fires for every costume/outfit/armor change alike and this addon’s data tables hold to a no-unverified-API-constants standard polling a signature built from data this file already computes gets the same result using only a bedrock-stable API. Updates land within ~2 seconds of a costume/outfit/armor change, whether or not the Settings panel happens to be open at the time.### 2.6.2- **Bug fix: costume/polymorph misclassification after applying an override.** Costumes and polymorphs share the same override key namespace (`costume_`) and the same detection path (`GetActiveCollectibleByType`), since ESO has no separate `COLLECTIBLE_CATEGORY_TYPE_POLYMORPH`. A prior fix that let polymorph overrides win over the data table accidentally checked `if polymorphOverride or polymorphEntry then` meaning applying an override to a *plain costume* made it get misclassified as a polymorph on the very next lookup (`result.source` flipped from `”costume”` to `”polymorph”`, and the breakdown slot key flipped from `””` to `””`). This is what caused the “Prefill from currently active item” dropdown in Settings to mislabel a costume as a “Polymorph” once you’d set an override on it. Classification now comes ONLY from table membership (`PolymorphInsulationById`/`PolymorphInsulation`), independent of whether an override exists; the override still applies to the resolved tier either way. The insulation *value* was never wrong only the source/label but the label feeds directly into the prefill dropdown and `/insulation`/`/costumeids` output, so this is worth updating for.### 2.6.1- **Override editor prefill.** Added a “Prefill from currently active item” dropdown above the Override Type/ID fields, listing whatever costume, polymorph, outfit piece, or armor style is *actually resolving right now* using the exact same precedence `GetInsulationBreakdown()` uses (polymorph/ costume beats outfit beats worn armor; an outfit slot with no style set falls back to the armor style showing through). Picking an entry auto-fills Override Type, the ID field, and the Insulation Tier dropdown with that item’s current resolved values, and shows the game’s own display name (`GetCollectibleName()` for outfits/costumes, the resolved English style name for armor) so there’s no need to cross-reference `/styleids`, `/outfitids`, or `/costumeids` by hand. “(manual entry)” remains available as the first choice for typing an arbitrary ID. The list refreshes whenever the panel opens, when **Refresh** is pressed, when an override is applied, or when overrides are reset.### 2.6.0- **Staggered tier system.** Replaced the free-floating 0100 continuous scale with eleven fixed tiers, staggered in increments of 10 from -10 to 90 (Magically Cooled, No Insulation, Minimal, Light, Coarse Light, Layered/Leather, Full Leather/Light Metal, Heavy Leather/Fur, Full Fur/Metal, Heavy Fur/Metal, Magically Heated). Every style, outfit piece, costume, and polymorph now resolves to one of these tiers via `Calc.SnapToTier()`. `-10`/`90` are reserved for entries flagged `magical = true` (Flame Atronach, Ice Wraith); everything else is clamped to the mundane 080 range before snapping.- **Per-slot percentage adjustment.** A style/outfit piece’s tier is now a full-body reference value; individual slots contribute a *percentage* of that tier based on body coverage (`slot_contribution = round(tier slotPercentage)`). `SlotCoverage`/`OutfitSlotCoverage` were rebalanced from summing to 0.90 up to exactly 1.00, so a full matching set reproduces its tier exactly as the total. Costumes and polymorphs are **not** slot-adjusted their snapped tier is the total, unadjusted, since they’re whole-body.- **Dropdown-based override editor.** The Settings panel’s “Insulation value” free-text editbox was replaced with an “Insulation tier” dropdown listing the eleven tiers by name, so an override can never drift off-tier. Programmatic `SetOverride()` calls snap any value passed in to the nearest tier instead of clamping 0100; `nil` (not `0`) now clears an override, since `0` is a legitimate tier (“No Insulation”).- **Saved-variable migration (v4 → v5).** Existing overrides from the old 0100 scale are snapped onto the nearest tier on first load rather than being discarded, preserving prior manual tuning as closely as the new scale allows.- **Bug fix:** `NearestMaterialForTarget()` (used by `/scanoutfitstyles` to guess a base material for unrecognized outfit pieces) was missing the 0.90 slot-weight-sum factor present in every other full-body reference calculation in this file, so its reference numbers (fur=100, leather=55.6, …) didn’t match the documented full-set reference table (fur=90, leather=50, …). Fixed to multiply by 0.90 like everywhere else.- `GetInsulationForStyle()` now simply delegates to the new `Calc.GetStyleTier()` instead of duplicating the formula.- Version bumped to 2.6.0 (`AddOnVersion: 8`), `SAVED_VARS_VERSION` to 5.### 2.5.3- **Corrected `LibAddonMenu-2.0` dependency floor**: was mistakenly bumped to `>=45` in 2.5.1, but LibAddonMenu’s own manifest documentation shows `43` as the latest available version, not `45`. Fixed to `>=43`. The 2.5.1 entry below has also been corrected to reflect the right number.### 2.5.2- **”What addons cannot do” compliance verified** against the actual ESOUI rules text (previously unverifiable due to a fetch issue with that specific thread see 2.5.1’s note). Checked all 24 prohibited-behavior items: this addon doesn’t touch the character-select/crown-store/scrying/Tribute UI, doesn’t read other players’ or NPCs’ positions, doesn’t change any visual effect/texture/sound/nameplate/camera/tooltip, doesn’t move/cast/interact with anything, doesn’t touch quickslot items, doesn’t write outside `SavedVariables`, doesn’t talk to external web services, and doesn’t share data between players. It’s a pure read-only calculator using documented API functions (the explicitly sanctioned “what addons could do” item #7), plus a settings panel and slash commands. **No code changes were required.** – Specifically confirmed: `CHAT_SYSTEM:AddMessage()`, used throughout this addon’s slash commands, is the standard local-only system-message print and is **not** the prohibited “send messages to chat directly” behavior (that rule targets auto-sending player-authored text into channels other players see, e.g. simulating Enter on `/say` or guild chat this addon never does that).### 2.5.1- **ESOUI release-rules compliance pass**, checked against the ESOUI “Please read: Before you release a new/update your addons” guidelines: – **AI-code disclosure added.** Per the rule requiring AI involvement to be named at the top of the addon description when the AI-written code/data hasn’t been independently validated, added a disclosure to both the manifest `## Description` and the top of this README. Most of this addon’s commands and data tables were built with AI assistance and are not yet confirmed working/performant in actual gameplay. – **Added the missing `## AddOnVersion` manifest tag.** Libraries need this so dependent addons can use `DependsOn: LibArmorInsulation>=N` version checks (the same mechanism this addon already uses for its own `LibAddonMenu-2.0` dependency). Starting value: `6` (one per tracked release so far); increment by 1 on every future release regardless of the semantic `## Version` string. – **`## APIVersion` updated** from the stale `101040` to `101049 101050` (current Live and PTS as of this pass), so the addon no longer shows as “Outdated” in-game. – **`LibAddonMenu-2.0` dependency floor bumped** from `>=33` to `>=43`, matching the version explicitly cited as current in the ESOUI rules thread at time of this pass. `>=` (rather than no version check) is required so the addon doesn’t silently load against a pre-Summerset LibStub-only build of LAM. – **Reviewed for global variable leaks** none found. The codebase already follows the recommended single-global-table pattern (`LibArmorInsulation`, `LibArmorInsulationData`, `LibArmorInsulationCalc`, `LibArmorInsulationSettings`), with all other identifiers declared `local`. – **Not independently verified this pass:** the “What AddOns must not do” rules thread (linked from the same guidelines post) could not be fetched to confirm compliance line-by-line at the time. **Resolved in 2.5.2** once the actual rules text was provided directly see that entry for the confirmed result.### 2.5.0- **152 manually-researched costume entries added to `CostumeInsulation`.** Sourced from UESP search-result snippets (direct page fetches are blocked by UESP’s bot detection, so coverage is best-effort rather than exhaustive roughly 134 of ~308 total ESO costumes were found with usable description text; the rest were left for `/scancostumes` to auto-rate). Each entry’s `flavorNote` carries a “ tag: – **high** the source text stated an explicit material (e.g. “studded leather doublet,” “Scaly Cloth Scraps,” “Fighters Guild Cool-Weather Gear”). – **medium** a strong contextual/regional inference (e.g. a scout outfit explicitly tied to a named cold-climate zone). – **low** a thematic guess with no explicit material cue in the source; these are reasonable starting points but are good candidates for manual re-verification, and `/scancostumes` will not override them since `CostumeInsulation` now outranks the scanner cache (see below). – One entry (**Old Orsinium Sentry**) corrects an earlier same-session guess after better source text was found later in the research pass.- **Costume resolver priority reordered.** `CostumeInsulation` (this manually-curated table) now outranks `sv.costumeCache` (the `/scancostumes` runtime cache) in `GetInsulationBreakdown()`. New priority order: user override → `CostumeInsulationById` → `CostumeInsulation` → `sv.costumeCache` → `DEFAULT_COSTUME`. Previously the scanner cache outranked this table, which meant a manually-verified entry could be silently shadowed by a coarser auto-rated guess.- **`OutfitStyles` gains a `Styles` fallback.** Most outfit-style collectibles are account-wide unlockable versions of existing crafting motifs, just reached through a different ID space. `GetOutfitStyleData()` now resolves an unrecognized collectible ID’s name via `GetCollectibleName()` (stripping a trailing `” Style”` suffix) and checks `Styles` before falling back to the `/scanoutfitstyles` cache so a style whose name matches an existing motif entry needs no new per-ID data at all. `/scanoutfitstyles` reports these as “ in its output.- **9 new motifs added to `Styles`** to close a coverage gap found while researching outfit styles: Swordthane, Dark Executioner, Necrom Armiger, Order of the Lamp, Ancient Mirrormoor, Companion Revelry, Fharun Moonlight, Chosen of Anu, Chosen of Padomay. These are Crown Crate/Collector’s Edition unlocks rather than world-found motif books, so they postdate the original “Motifs 1129” coverage. Material assignments are UESP-sourced where the style explicitly resembles an existing entry (e.g. Dark Executioner → resembles Dark Brotherhood armor); the rest are lower-confidence thematic inferences from cosmic-duality/regional lore with no explicit material description available.### 2.4.0- **`/scancostumes` now scans description text, not just name.** `AutoRate` checks the costume’s name against the keyword list first (names are usually more deliberately worded), then falls back to `GetCollectibleDescription()` flavor text if the name has no hit. Each cache entry now records a `matchSource` (`”name”`, `”description”`, or `”none”`) so genuinely unmatched entries sitting on the generic 50 fallback can be identified.- **New `/scanoutfitstyles` command.** Outfit style pages had no auto-detection path at all (`OutfitStyles` was a hand-only stub table). This walks every unlocked outfit’s 7 slots (same enumeration as `/outfitids`) and, for any collectible ID not already in `OutfitStyles`, keyword-rates it via name + description and writes a guessed `{baseMaterial, coverage, flavorBonus}` into the new `sv.outfitStyleCache`. `GetOutfitStyleData()` now checks this cache as a fallback before `OutfitStyles`.- **New `/costumesneedreview` and `/outfitstylesneedreview` commands.** Filter each respective cache down to entries where the keyword scan found no match in either name or description a short worklist for manual UESP-backed overrides instead of scrolling the full scan output.- **Shared keyword table.** `KEYWORD_RATINGS` and `AutoRate` were hoisted out of `/scancostumes` to file scope so `/scanoutfitstyles` draws from the same list a new pattern only needs adding once.- **Removed an unused dynamic costume-discovery path.** An earlier in-progress approach (`BuildCostumeKeywordMap()`, brute-force probing every collectible ID 1→N) was removed before release it would have silently outranked the better-designed `/scancostumes` + `sv.costumeCache` resolution order. Not shipped in any prior version; mentioned here for the record.- **Saved variables bumped to version 4;** v2/v3 saves are migrated automatically, preserving existing overrides and caches.### 2.3.0- **Name-keyed style table.** `LibArmorInsulationData.Styles` is now keyed by the English name returned by `GetItemStyleName()` (e.g. “, “) instead of raw `StyleItemIndex` integers. This mirrors the zone-ID lesson: style integers can be reassigned between ESO API updates, but the English name is stable.- **Runtime ID maps built at login.** `LibArmorInsulationCalc.BuildStyleIdMaps()` is called during `EVENT_ADD_ON_LOADED`. It iterates `GetItemStyleName(i)` for `i = 1, GetHighestItemStyleId()` and populates two tables: – `LibArmorInsulationData.StyleIdByName` `{ = 5, }` – `LibArmorInsulationData.StyleNameById` `{ = “Nord”, }` These maps are rebuilt every login from live game data, so any future ZOS reassignment of integer IDs is handled automatically without a data-table update.- **Lookup chain in Calculator.** All style lookups now follow: `styleId → StyleNameById → Styles → DEFAULT`. The integer from `GetItemLinkItemStyle()` is still accepted everywhere in the public API; it is resolved to a name internally and never stored as a persistent key.- **`styleName` added to breakdown results.** Each slot entry in `GetInsulationBreakdown().slots` now includes a `styleName` field (string or nil) alongside the existing `styleId`, so callers can display a human-readable name without performing their own lookup.- **Override keys unchanged.** Saved-variable override keys remain `”style_N”` (integer-based) because the player set them against a specific integer at a known point in time. They continue to work the integer is used only as a unique token for the saved-variable key, not for a data-table lookup.### 2.2.0- **Full style coverage:** `LibArmorInsulationData.Styles` now contains entries for all crafting-motif style IDs known as of ESO Update 49 (motifs 1129, IDs 1129). Previously only ~67 IDs were populated; ~62 motifs from the Thieves Guild, Dark Brotherhood, Morrowind, Summerset, Elsweyr, Greymoor, Blackwood, High Isle, Necrom, and Gold Road chapters were missing entirely.- **Corrected several ID-to-name mappings** that were shifted by one due to a miscount of the gap between the racial styles (110) and the first post-racial motifs: – Telvanni was “; corrected to “ (Motif 50). – Dragonscale was “; ID 36 is Dark Brotherhood (Motif 36). Dragonscale is not a craftable motif removed; dragon-scale aesthetics are covered by individual dungeon-set pieces with no motif ID. – Snowhawk “ was an invention with no confirmed ITEM_STYLE_* counterpart; Snowhawk is an **outfit-style collectible only** (not a motif). Entry removed from `Styles`; use the `OutfitStyles` collectible table instead. – IDs 8089 ancestral styles renumbered to match confirmed Motifs 8795. – IDs 90105 updated to match Greymoor / Blackwood / High Isle motif numbering.- **Zone ID statement evaluated:** The claim that “ESO zone IDs are large non-sequential integers the only stable identifier is the English zone name `BuildZoneIdMaps()` inverts the name→ID mapping” does **not apply to style IDs** and has **no relevance to this library**. Style IDs (`StyleItemIndex` / `ITEM_STYLE_*`) are small sequential integers starting at 1 and are stable across API updates the exact opposite of zone IDs. This library does not use `LibZone`, `BuildZoneIdMaps()`, or any zone-ID machinery. No changes were required.### 2.1.0- Outfit slots now look up insulation by **collectible ID** via `ZO_OUTFIT_MANAGER` rather than by `ITEM_STYLE_*` ID, matching how ESO actually stores outfit style data internally.- Added `LibArmorInsulationData.OutfitStyles` table (keyed by collectible ID) separate from `Styles` (keyed by `ITEM_STYLE_*`).- `SetOverride` now accepts an `idType` parameter (`”style”`, `”outfit”`, `”costume”`) to disambiguate the three ID spaces.- Added `sv.costumeCache` a persistent per-account cache populated by `/scancostumes`.- New slash commands: `/costumeids`, `/scancostumes`, `/clearcostumecache`, `/outfitids`, `/outfitactive`, `/diagcollectibles`.- Added `LibArmorInsulationData.CostumeInsulationById` (collectible ID keyed) alongside the existing name-keyed `CostumeInsulation` table.- Saved variables bumped to version 3; v2 saves are migrated automatically.- Detection of active outfit changed from `GetActiveOutfitIndex()` to `GetEquippedOutfitIndex()` (confirmed correct ESO API function).### 1.0.0- Initial release.—## LicenseMIT free to use, modify, and redistribute with attribution.

0

Frostfall (3.4.11)

# Frostfall Temperature System for ESO### Version 3.4.11 | Inspired by Frostfall (Skyrim)*by @Kreksar5 and Claude.ai*> Thematically inspired by *Frostfall*, the well-known Skyrim mod by> **Chesko** name and concept used as an homage, **not a port, and not> affiliated with or endorsed by Chesko or Frostfall’s other contributors.**> **AI-ASSISTED ADDON.** Written with Claude.ai. Core mechanics have been> iteratively refined and bug-fixed across many versions, but this should> still be treated as not fully independently validated in-game until> confirmed through extended play-testing.—## Credits- **Frostfall Hypothermia Camping Survival** (the Skyrim mod) by **Chesko**: the name and the general hypothermia/insulation concept are used as a direct homage. This addon is an original implementation built for ESO’s own API and mechanics no code, assets, or data from the Skyrim mod were used or could be (different engine, different game).- **RolePlayNeeds Tamriel Survival!** by **matheusbk2**: two implementation details were confirmed by inspecting its actual published source (checked directly against the official v0.7 BETA release) the `EVENT_LOOT_RECEIVED` argument signature (position 5, not 6, is the item-type integer), and the disease-overlay window construction pattern (`CreateTopLevelWindow` → `SetAnchorFill()` → `SetMouseEnabled(false)` → child `CT_TEXTURE` with its own `SetAnchorFill()`, alpha controlled on the parent window) that this addon’s hot/cold overlays follow. No code was copied; Frostfall is an original implementation. **Correction:** a third item a `RPN_REAGENT_TRAITS` static item-ID lookup table for alchemy traits was previously credited to RolePlayNeeds here and in the v3.3.0 notes below. That table does not exist in RolePlayNeeds’ published source; RolePlayNeeds has no reagent-trait handling at all. This addon’s `FV.SPELL_RESIST_REAGENT_IDS` table is an independent lookup this project built itself it was mistakenly attributed to RolePlayNeeds (likely confused with a local, personally- modified copy of RolePlayNeeds that was never published), and the credit has been removed.### Overlay art creditThe hot/cold screen-overlay images (`HOT_OVERLAY.dds`, `COLD_OVERLAY.dds`)were generated using AI text-to-image tools (https://perchance.org/ai-text-to-image-generator) and Google’sGemini Image Creator and edited/converted to the game’s `.dds` formatusing Paint.NET. They are not hand-drawn or sourced from ESO’s own artassets.—## OverviewFrostfall adds a fully-featured ambient temperature and survival system to Elder Scrolls Online. Every zone has an estimated ambient temperature based on its lore and biome. Your armor, costume, and outfit style all contribute **insulation**. Gear sets grant insulation bonuses (or penalties). Swimming affects your effective temperature. At temperature extremes, screen overlays and emotes bring the experience to life.**Insulation semantics:** High insulation traps body heat excellent in cold zones, but causes overheating in hot zones. Low insulation lets heat escape comfortable in heat, but leaves you exposed to cold.—## What’s New### v3.4.11 documentation accuracy passA full review of this README against the actual current code and againstLibZoneTemp/LibArmorInsulation’s real current data (the developer suppliedthe official RolePlayNeeds release for direct comparison). Found and fixed:- **RolePlayNeeds misattribution**: a `RPN_REAGENT_TRAITS` static item-ID lookup table was credited to RolePlayNeeds no such table exists in RolePlayNeeds’ published source (confirmed against the official v0.7 BETA release; RolePlayNeeds has no reagent-trait handling at all). This addon’s own `FV.SPELL_RESIST_REAGENT_IDS` table is an independent lookup this project built itself. The `EVENT_LOOT_RECEIVED` argument-signature and overlay-window-anchoring credits were checked too and are genuinely accurate kept as-is.- **Zone Temperature Reference table was completely wrong** every one of the 17 listed values was inaccurate, most by 3080C (e.g. Coldharbour listed as 2C, actually -8C; The Deadlands listed as 85C, actually 54C). Rebuilt from `LibZoneTemp.lua`’s actual `ZONE_BASE_TEMPS_BY_NAME` table. Also corrected the “80+ zones” / range claims in the Features overview (actually 1,000+ zones and sub-zones, -16C to 55C).- **Armor Insulation Reference table was from before the v2.6.0 staggered-tier rewrite** raw pre-snap scores that no longer correspond to any real output of the current formula, plus four listed styles/costumes (Voidsteel, Nightmare, Soul Shriven, Bear Raiment Costume) that don’t exist anywhere in the current data. Rebuilt with real entries and tiers computed through the actual current formula and `Calc.SnapToTier()`.- **Thermal direction was backwards for several Daedric-aligned pieces**: Daedric, Ancient Daedric, Dremora, and Waking Flame were all described as heat-generating with above-average insulation; the actual code has all four with a *negative* `flavorBonus` (explicitly cold-themed flavor text), landing them at or near the bottom of the range, not the top.- **Removed an entirely fictional “Set Insulation Bonuses” feature** a full section describing gear sets granting flat insulation bonuses, “detected via LibArmorInsulation” with its own config panel. No part of this exists in either addon: no set-detection code, no bonus data table, no such config panel. Also removed the matching “active set bonus” claim from the HUD Display section.- **Corrected the claimed cultural-origin insulation ordering** (“Nord > Orc > Breton > Imperial > Khajiit > Argonian”) the real computed order is Nord > Breton > Khajiit/Argonian/Orc (tied) > Imperial.### v3.4.10 settings-panel sync- **Fixed the settings panel’s author/version fields**, which were out of sync with the manifest and README: `author` incorrectly read “Frostfall” (the addon’s own title) instead of the actual author, and `version` was hardcoded to a stale `”3.4.2″` (the internal `FV.VERSION` constant was also stale, at `”3.4.4″`). The panel now reads `author = “@Kreksar5 and Claude.ai”` and `version = FV.VERSION`, and `FV.VERSION` itself is kept in sync with the manifest `## Version` going forward.### v3.4.9 overlay art credit- **Added an “Overlay art credit” note** to the Credits section, crediting the Perchance AI Text-to-Image Generator and Google’s Gemini Image Creator for generating `HOT_OVERLAY.dds` and `COLD_OVERLAY.dds`, and Paint.NET for editing/converting them to the game’s `.dds` format.### v3.4.8 author credit- **Standardized the author credit** to `@Kreksar5 and Claude.ai` in the `## Author` manifest field and this README’s byline, and named Claude.ai specifically (rather than generic “AI assistance”) in the manifest description and the AI-assistance disclosure above, matching the crediting convention used across this addon’s companion libraries.### v3.4.7 non-affiliation disclaimer- **Added an explicit “not a port, not affiliated with or endorsed by Chesko” disclaimer** for the Skyrim mod *Frostfall*, matching the disclaimer Realistic Needs and Diseases already carries for its own Skyrim namesake. This addon reuses Chesko’s mod name and general concept as a homage Chesko’s own permissions pages ask to be contacted before the mod’s name or work is reused elsewhere, so this addon now says plainly, in both the manifest description and this README, that it is an independent, unaffiliated ESO implementation with no shared code or assets (impossible between these two games’ engines regardless).- **Expanded the Credits section** to name Chesko and the Skyrim mod directly, rather than only crediting RolePlayNeeds for implementation details.### v3.4.6 ESOUI release-rules compliance pass- **Corrected the `## Author` manifest field**, which incorrectly read “Frostfall” (the addon’s own title) instead of the actual author.- **Added the required `## AddOnVersion` tag** (previously missing entirely this is the integer the ingame addon manager and Minion use to detect updates, separate from the informational `## Version` tag). Started at 6, comfortably above the `>=3` floor that Realistic Needs and Diseases’ `OptionalDependsOn` line already checks for.- **Added a version floor (`>=1`) to the `LibClockTST` dependency**, which previously had none.- **Added the required AI-assistance disclosure** to the manifest description and this README, per ESOUI’s addon release rules.- **Added a Credits section** naming RolePlayNeeds (matheusbk2) for the implementation details referenced during development.### v3.4.5 API compliance audit- **Full API audit against the official ESOUI API 101050 documentation.** Every function call, method call, and constant referenced across the addon was cross-checked against the API doc and, where the doc didn’t cover it (manager singletons, `ZO_` helpers, third-party libraries), against the live ESOUI source.- **Removed the entire weather feature** (`FV:UpdateWeatherState`, `FV:OnWeatherChanged`, the `EVENT_WEATHER_CHANGED` registration, and the precipitation-drag term in the temperature drift calculation). Neither `EVENT_WEATHER_CHANGED` nor any of the six `WEATHER_*` constants (`WEATHER_RAIN`, `WEATHER_SNOW`, `WEATHER_THUNDER`, `WEATHER_ASHCLOUD`, `WEATHER_FOG`, `WEATHER_CLOUDY`) exist anywhere in the ESO addon API ESO does not expose live weather state to addons at all, so this feature could never have worked. Worse, registering for a `nil` event code at load time risked erroring out of the whole `OnPlayerActivated` init sequence, breaking the drift-update timer and emote-loop registrations that ran after it. Removed the now-dead `isRaining`/`isSnowing`/`isStorming`/ `isSunny`/`weatherType` state fields and updated `/ff status`, the debug log line, and this README to match.- Everything else checked out: `EVENT_MANAGER`, `WINDOW_MANAGER`, `SCENE_MANAGER`, `PLAYER_EMOTE_MANAGER`, `ZO_Alert`, `ZO_PreHook`, and all LibAddonMenu/LibSavedVars/LibZone/LibClockTST calls are legitimate and correctly used.### v3.4.4 dependency version correction- **Corrected `LibAddonMenu-2.0` dependency floor**: was mistakenly bumped to `>=45` in 3.4.3, but LibAddonMenu’s own manifest documentation shows `43` as the latest available version, not `45`. Fixed to `>=43`. The 3.4.3 entry below has also been corrected to reflect the right number.- **`LibZoneTemp` dependency floor bumped** from `>=9` to `>=11`, following LibZoneTemp’s own version corrections in the same vein.### v3.4.3 ESOUI compliance pass- **Fixed a manifest bug: 5 separate `## DependsOn:` lines consolidated into 1.** Per the addon manifest spec, multiple non-optional dependencies must be space-separated on a single `## DependsOn:` line; repeating the directive across several lines risks the manifest parser only honoring the last occurrence, which would have silently dropped the `LibClockTST`, `LibAddonMenu-2.0`, `LibZone`, and `LibZoneTemp` checks (leaving only `LibArmorInsulation` actually enforced).- **Added missing version floors** (`>=`) for `LibAddonMenu-2.0` (`>=43`), `LibZoneTemp` (`>=9`), and `LibArmorInsulation` (`>=7`), matching their current `## AddOnVersion` values. `LibClockTST` still has no version floor its current `AddOnVersion` wasn’t available to check during this pass; recommend confirming and adding one.- **`## APIVersion` updated** from the stale `101043` to `101049 101050` (current Live/PTS), and the README’s compatibility section synced to match.- **Reviewed for global variable leaks and “what addons cannot do” compliance** none found. The reagent-consumption mechanic only *listens* for `EVENT_INVENTORY_SINGLE_SLOT_UPDATE` after the player manually eats/uses something; it never calls `UseItem` or any consume/cast/interact function itself, so it doesn’t touch the quickslot-automation restrictions.### v3.4.2- **Reagent consumption detection now ignores bank activity.** Withdrawing or depositing a reagent from the personal bank or guild bank fires the same `EVENT_INVENTORY_SINGLE_SLOT_UPDATE` as eating it, so the spell-resist buff trigger is now also gated off while either bank window is open (`EVENT_OPEN_BANK`/`EVENT_CLOSE_BANK`, `EVENT_OPEN_GUILD_BANK`/`EVENT_CLOSE_GUILD_BANK`), matching the existing merchant/crafting-station gating.### v3.4.1 (bugfix)- **Fixed: reagent consumption detection was completely broken.** `GetMedicinalUseRank()` (used to scale the spell-resist buff’s duration) called `GetCraftingSkillLineIndices()` and referenced a `SKILL_TYPE_CRAFTING` constant neither exists in the ESO UI API. The resulting Lua error aborted the whole consumption handler before it could ever apply the buff, so eating a qualifying reagent did nothing. Replaced with `GetNumSkillLines(SKILL_TYPE_TRADESKILL)` + `GetNumSkillAbilities()` + `GetSkillAbilityInfo()`, all verified directly against esoui/esoui’s `ESOUIDocumentation.txt`.### v3.4.0- **Spell-resist reagent buff completed** added the remaining two confirmed item IDs (Clam Gall `139020`, White Cap `30154`) to `FV.SPELL_RESIST_REAGENT_IDS`, alongside Bugloss and Mudcrab Chitin from 3.3.0. All four canonical “Increase Spell Resist” reagents (per UESP) now trigger the buff.### v3.3.0- **New: Spell-resist reagent temperature buff** consuming an alchemy reagent with the “Increase Spell Resist” trait (Bugloss, Clam Gall, Mudcrab Chitin, White Cap) steadies the player’s effective temperature toward neutral (22C, the midpoint of the comfortable band), capped at a 10C shift in either direction. – Lasts 30 real-world minutes, extended by 10%/20%/30% if the player has rank 1/2/3 of the Alchemy passive **Medicinal Use**. – Eating another qualifying reagent while the buff is active resets the timer instead of stacking. – Fires a fade warning once per minute during the last 5 minutes of the buff. – The steadying offset is **recalculated live** from the player’s current real temperature differential every time it’s applied it is not a fixed snapshot taken at the moment the reagent was eaten, so it keeps tracking the player’s true temperature as they move through zones/weather while the buff is up. – Uses a static item-ID lookup table (`FV.SPELL_RESIST_REAGENT_IDS`) built for this addon, since alchemy trait APIs only work at an open crafting station. *(Corrected: this was previously described as following the same pattern as RolePlayNeeds’ “`RPN_REAGENT_TRAITS`” no such table exists in RolePlayNeeds’ published source; see the correction in Credits above.)* – Internally, player temperature is now split into a “true” physical value (driven by ambient/weather/swim drift, unaffected by the buff) and an effective/displayed value (`FV:GetEffectiveTemp()`) that HUD, overlay, emotes, and band alerts all read from.### v3.2.0- **ConfigMenu synced with Frostfall.lua thresholds** the emote and threshold descriptions in the settings panel now reflect the correct v3.1.5 values (HOT 35C/95F, HEAT_DANGER 41C/105F) instead of the old stale values (27C/80F and 38C/100F).- **Slash command renamed: `/fv` → `/ff`** The short-form slash command is now `/ff` to avoid conflicts. `/frostfall` continues to work as before.- **ConfigMenu panel version updated** The LAM panel version string now correctly reads `3.2.0`.### v3.1.5 (included in this release)- Updated all temperature thresholds to more logical/reasonable values: – `COMFORTABLE_LO` raised from 16C → 20C (61F → 68F) – `COMFORTABLE_HI` raised from 26C → 24C (79F → 75F) *(reordered now correctly below WARM)* – `WARM` raised from 21C → 26C (70F → 79F) – `HOT` raised from 27C → 35C (80F → 95F) – `HEAT_DANGER` raised from 38C → 41C (100F → 105F)- Fixed band-transition comparison operators (`<` → `<=`) so boundary temperatures are correctly classified.- OverlayEffects: pre-computes both cold and hot alpha before applying either, eliminating a mutual-exclusion bug that could mask the hot overlay.- OverlayEffects: hot overlay comments and ramp references updated to match the new HOT (35C) and HEAT_DANGER (41C) thresholds.### v3.1.4- Fixed water loot handler was reading the 6th `EVENT_LOOT_RECEIVED` argument instead of the correct 5th (`itemType`). Now matches RolePlayNeeds exactly.—## Features### Zone Temperature System- **1,000+ zones and sub-zones** have carefully estimated base temperatures in C- Temperatures range from Icereach (-16C) to City of Ash II (55C) see the corrected reference table below for a curated selection of overland zones- Zone temperature provided by **LibZoneTemp**### Armor & Costume InsulationPriority order (first match wins):1. **Costume** Crown Store cosmetics; insulation based on material and coverage2. **Outfit Style** Outfit system style overrides; checks chest slot style3. **Base Armor Style** Your equipped armor’s crafting style**100+ styles** have insulation values calculated from the **style** alone (not the set name):- Skin coverage (how much of the body is covered)- Material (fur/hide > plate > leather > cloth > silks)- Cultural origin climate *(corrected: previously listed as “Nord > Orc > Breton > Imperial > Khajiit > Argonian”, but the real computed tier order is Nord (80) > Breton (50) > Khajiit/Argonian/Orc (30, tied) > Imperial (20) Orc and Imperial were both misplaced)*- Magical/special thermal properties (a small number of Daedric-aligned and undead-adjacent pieces are flavor-adjusted **colder**, not hotter see below)Certain unique pieces have **flavor-adjusted** insulation based on theirin-game descriptions. *(Corrected: this list previously claimed several ofthese were heat-generating and gave one nonexistent-style example; theactual code has the opposite thermal direction for the Daedric-alignedpieces, and three of the four “very low insulation” examples don’t existin the current data at all.)*- **Daedric / Ancient Daedric / Dremora / Xivkyn / Stalhrim Frostcaster** described in-code as radiating unnatural **cold**, not heat → these land at or near the bottom of the mundane range (tier 010), not the top- **Waking Flame** despite the fire theming, its actual flavor bonus is a small negative one (“carries a mild chill”) → mid-range tier (50), not especially warm- **Flame Atronach (costume)** living flame → clamped to the maximum tier (90, not 95 the raw 92 score is capped by `Calc.SnapToTier`)- **Frost Atronach (costume) / Ice Wraith (polymorph)** living ice/frost → clamped to the minimum tier (-10), the coldest a mundane or magical source can register- **Apostle** despite the “regulated temperature design” flavor text, its actual tier (30) is below the 50 midpoint, not neutral- *(Voidsteel, Nightmare, and Soul Shriven previously listed here as very-low-insulation examples do not exist anywhere in the current style/costume/polymorph data. The closest real match to “Soul Shriven” is the “Soul-Shriven” style, tier 10, no flavor bonus.)**(**Removed: “Set Insulation Bonuses” section.** This README previouslydescribed a whole feature here a table of specific gear sets each givinga flat additive insulation bonus/penalty, “detected via LibArmorInsulation”and configurable under a “Set Insulation Bonuses” panel in `/ff config`.No part of this exists: there’s no set-detection code (no`GetItemLinkSetInfo`/equivalent call) and no set-bonus data table anywherein either this addon or LibArmorInsulation, and no such panel in`ConfigMenu.lua`. The insulation sources that actually exist are exactlythe three listed under “Armor & Costume Insulation” above costume,outfit style, and base armor style with no separate set-based layer ontop. If a set-bonus feature gets built for real in the future, it belongsback here.)*### SwimmingSwimming in open water equilibrates your body temperature toward the water temperature, partially bypassing insulation. Cold-zone water (below 15C) is especially dangerous (2.5x drag rate). Thick armor provides some resistance but far less than on land.### Environmental Temperature Mechanics- **Water ingredient loot** Looting an alchemy water solvent cools you by 5C (only if you are already above `COMFORTABLE_HI`).- **Crafting station interaction** Opening a provisioning or smithing station warms you by 5C (only if below `COMFORTABLE_LO`). Rate-limited to once per minute.### Temperature Thresholds (all in C)| Threshold | C | F | Meaning ||———–|—-|—-|———|| FREEZE_DANGER | −10 | 14 | Hypothermia danger || VERY_COLD | 0 | 32 | Very cold shiver emote || COLD | 10 | 50 | Cold shiver emote || COMFORTABLE_LO | 20 | 68 | Lower edge of comfort zone || COMFORTABLE_HI | 24 | 75 | Upper edge of comfort zone || WARM | 26 | 79 | Warm (no effect) || HOT | 35 | 95 | Hot wipe-brow emote, heat overlay begins || HEAT_DANGER | 41 | 105 | Scorching breathless emote, full heat overlay |### HUD Display- Compact thermometer widget (draggable)- Color-coded temperature bar and value- Status label (COMFORTABLE, COLD, OVERHEATING, etc.)- Insulation value and source displayed (e.g. `80 (armor)`) *(corrected: previously also claimed an “active set bonus” was shown here; no such feature exists see the note on the removed “Set Insulation Bonuses” section above)*### Configuration MenuAccessible via `/ff config` or the ESO addon settings panel (LibAddonMenu-2.0):- Enable/disable the system entirely- Toggle HUD, overlay, emotes, and sounds- Scale and opacity controls for the HUD- Emote dropdowns for each temperature band, populated live from your installed emotes—## Installation1. Download and extract the `Frostfall` folder2. Place it in: `DocumentsElder Scrolls OnlineliveAddOnsFrostfall`3. Install all required dependencies (see below) Minion handles this automatically4. Launch ESO, enable the addon in the AddOns menu—## Slash Commands| Command | Description ||———|————-|| `/ff` or `/frostfall` | Show help || `/ff status` | Print current temperature state to chat || `/ff config` | Open configuration menu || `/ff debug` | Toggle debug logging || `/ff toggle` | Enable/disable Frostfall || `/ff findEmote ` | Search for an emote by name and print its stable emoteId |—## Zone Temperature Reference (Selected)*(Corrected every value in this table was previously wrong, by a widemargin in most cases (e.g. Coldharbour listed as a mild 2C when it’sactually -8C; The Deadlands listed as 85C when it’s actually 54C). Thetable below is pulled directly from `LibZoneTemp.lua`’s current`ZONE_BASE_TEMPS_BY_NAME` table.)*| Zone | Temperature | Climate ||——|————|———|| Western Skyrim | -10C | Very cold, snowy Nordic holds || Bleakrock Isle | -8C | Icy island cliffs, sparse forests || Coldharbour | -8C | Bleak grey sky, cold and lifeless || Wrothgar | -8C | Orsinium highlands, bitterly cold winters || Eastmarch | -2C | Frozen wastes, volcanic tundra || Rivenspire | 4C | Bleak, windswept moors || The Rift | 4C | Relatively temperate, rich autumnal forests || Cyrodiil | 17C | Temperate central forests and plains || Summerset | 18C | Mild, pleasant Mediterranean climate || Auridon | 20C | Temperate Mediterranean gardens and architecture || Gold Coast | 22C | Pleasant climate, warmed by the Abecean Sea || Murkmire | 34C | Deep tropical marshland jungle || Hew’s Bane | 36C | Barren, scorching desert peninsula || Vvardenfell | 38C | Volcanic island, arid ash wastes || Northern Elsweyr | 40C | Hot Anequine savanna and Scar desert || Alik’r Desert | 46C | Arid Hammerfell wasteland, scorching sandstorms || The Deadlands | 54C | Mehrunes Dagon’s hellfire Oblivion realm |—## Armor Insulation Reference (Selected)*(Corrected this table previously listed 18 entries with pre-tier-systemraw scores from before the v2.6.0 staggered-tier rewrite, four of whichVoidsteel, Nightmare, Soul Shriven, and Bear Raiment Costume don’t existanywhere in the current style/costume data at all. Several “flavor-adjusted”notes also had the thermal direction backwards: Daedric, Dremora, WakingFlame, and Ancient Daedric are all written in the code as **cold**-radiating(negative `flavorBonus`), not heat-generating. The table below is rebuiltfrom `LibArmorInsulation_StyleData.lua`’s actual current entries, with tierscomputed through the real formula and `Calc.SnapToTier()`.)*| Style | Insulation | Notes ||——-|———–|——-|| Flame Atronach (costume) | 90 ★ | Body of living fire extreme warmth || Nord | 80 | Fur construction, capped at the mundane ceiling (raw score ~107) || Werewolf (polymorph) | 80 | Dense fur pelt and elevated body temperature || Pyre Watch | 70 | Fire-tempered treatment provides insulating char layer || Silver Dawn | 70 | Heavy-leather motif, no flavor bonus || Waking Flame | 50 | Deadlands-tinged construction carries a **mild chill** (not heat, despite the fire theming) || Mercenary | 50 | Practical layered construction for road travel || Wood Elf | 30 | Light cloth racial armor, no flavor bonus || Khajiit | 30 | Light hide racial armor, no flavor bonus || Barbaric | 20 | Thin hide motif, low coverage || Fang Lair | 20 | Dragon bones carry the cold of death || Dremora | 10 | Emanates the consuming cold of Coldharbour || Storm Atronach (costume) | 10 | Elemental form provides no thermal protection || Daedric | 0 | Radiates unnatural cold into the wearer’s bones || Stalhrim Frostcaster | 0 | Stalhrim plates actively radiate cold || Frost Atronach (costume) | -10 ★ | Body of living frost actively leeches warmth || Ice Wraith (polymorph) | -10 ★ | Body of living ice aggressively cold |★ = `magical = true` clamped to the full -10..90 tier range instead of themundane 0..80 range reserved for ordinary materials.—## DependenciesAll are **required**. Minion (the standard ESO addon manager) will install them automatically.| Library | Source | Purpose ||———|——–|———|| LibAddonMenu-2.0 | (https://www.esoui.com/downloads/info7-LibAddonMenu.html) | Settings panel UI || LibZoneTemp | ESOUI | Zone ambient temperature data || LibArmorInsulation | ESOUI | Armor insulation breakdown |—## Compatibility- ESO API Version: 101049+- Works with all ESO chapters and DLC- Compatible with outfit system, costume system, and Crown Store collectibles—## Notes on Temperature CalculationsAll zone temperatures and armor insulation values are **estimates** based on lore descriptions, visual design, cultural origin, and material analysis. Insulation is calculated from the **visual style** of the armor, not the set name. Unique pieces with flavor text describing thermal properties have been individually adjusted. Use the override system to tune anything that doesn’t feel right for your playstyle.The temperature system is **purely cosmetic** it does not affect actual gameplay stats, damage, or character mechanics. It is an immersion and roleplay tool.

0

Realistic Needs and Diseases (0.19.5)

# Realistic Needs and Diseases**Version 0.19.5** ESO API 101049 101050 License: MIT*by @Kreksar5 and Claude.ai*> Thematically inspired by *Realistic Needs and Diseases*, the well-known> Skyrim mod name and concept used as an homage, **not a port, and not> affiliated with or endorsed by that mod’s authors.**> **AI-ASSISTED ADDON, UNTESTED.** Built with Claude.ai, not yet run in a> live client. Several pieces are explicitly flagged below as> unverified/best-guess and need confirming in-game before you trust them.## Credits- **RolePlayNeeds Tamriel Survival!** (the ESOUI addon) by **matheusbk2**: two implementation details were confirmed by inspecting its actual published source (checked directly against the official v0.7 BETA release) the `bindings.xml`/keybind naming convention (`RPN_CHECK_NEEDS` action name, `RPN_CheckNeeds()` handler mirrored here as `RND_CHECK_NEEDS`/`RND_CheckNeeds()`), and the inventory-seed-on-login fix for reliable first-consumption detection (`ForceInventoryScan()` called from `EVENT_PLAYER_ACTIVATED`, seeding a `lastInventoryState` table before any inventory event can fire this addon’s equivalent is `SeedLastSlotState()`). No code was copied; this addon is an original implementation, not a port or derivative (see disclaimer above). **Correction:** three other items were previously credited to RolePlayNeeds here a `RPN_REAGENT_TRAITS` alchemy-trait lookup table, a “two-stage” water-loot detection fix, and a labeled-row HUD/window layout. None of these exist in RolePlayNeeds’ actual published source. They were mistakenly attributed to RPN when they were really from a local, personally-modified copy of RolePlayNeeds that was never published the credit has been removed, and the affected code comments in `RealisticNeedsAndDiseases_Data.lua` and `RealisticNeedsAndDiseases.lua` corrected to no longer claim RPN corroboration for that data.- **No Interact** by **Rhyono**: the world-object “Sit” interaction detection (`RETICLE:TryHandlingInteraction` hook and the `INTERACTIVE_WHEEL_MANAGER`/ formerly `FISHING_MANAGER` reassignment technique for catching interact keypresses) follows the same technique this addon uses to read reticle state and intercept interactions. No code was copied.A from-scratch survival-needs and disease addon for ESO: hunger, thirst, andfatigue meters that decay naturally over time, accelerated (never slowed) byenvironmental temperature, plus 5 independently-trackable diseases cured byspecific alchemy ingredients rather than potions.This is an original implementation not a patch or derivative ofRolePlayNeeds (or anything else). See `RealisticNeedsAndDiseases_design_notes`section below for what changed across this build’s iterations.—## Needs- **Hunger**, **Thirst**, **Fatigue**, each 0100. All decay/restore rates and warning thresholds below are now **player-adjustable in Settings**.- **Decay is always-on at a natural baseline rate** (default: hunger empties in 4h, thirst in 3h, fatigue in 6h all adjustable). Temperature never reduces decay below that baseline, it only ever accelerates it on top. Inside the comfort band (10C25C), you get pure baseline decay. Outside it, the relevant meter(s) drain up to 22.5x faster. – Hot environments → thirst accelerates. – Cold environments → hunger and fatigue accelerate.- Eating restores hunger (default +30, adjustable), drinking restores thirst (default +30, adjustable).- **Harvesting an alchemy water node in the wild also restores thirst directly** (default +15, adjustable) uses the same confirmed alchemy-water-solvent item IDs already validated elsewhere in this project (883, 1187, 4570, 2326523268, 64500, 64501), via `EVENT_LOOT_RECEIVED`. ⚠️ This is a simpler single-stage v1 see the in-code warning about the event’s unverified parameter order. (An earlier version of this note claimed RolePlayNeeds’ published source needed a two-stage detection pattern for this; that wasn’t accurate see the correction in Credits.)- Temperature source: `Frostfall:GetEffectiveTemp()` preferred, `LibZoneTemp.GetCurrentTemperature()` fallback, flat baseline otherwise.### How fatigue works (and how to recover)Fatigue is the simplest of the three meters by design there’s no “activitytracking” (no movement-speed sampling, no combat-time accounting, unlikeRolePlayNeeds’ approach). It’s purely:1. **Time-based baseline drain.** Fatigue ticks down at a flat natural rate (default: empties over 6 hours of played time) every 5-second tick, identical in mechanism to hunger and thirst there’s nothing fatigue- specific about *what* drains it, only the rate.2. **Temperature-accelerated, in both directions.** Unlike hunger (cold-only) and thirst (hot-only), fatigue accelerates at **either** temperature extreme being too cold *or* too hot tires you out faster, up to 2x the baseline rate, ramping over the same 20C-beyond-comfort-band range as the other two meters (see `Calculator.GetFatigueDecayRate()`).3. **Recovery now exists (as of 0.7.0)** three mechanics, all gated on not moving and being out of combat: standing still for a few minutes (slow regen), sitting for about a minute (faster regen), or sleeping/meditating for a while (full restore, with an optional fade-to-black effect). See the “Fatigue recovery” section below for details. Before 0.7.0, this section used to note fatigue recovery as a missing/incomplete design that gap is now closed.—### Overlay art creditThe disease status-overlay images (`Frostbite.dds`, `Heatstroke.dds`,`MagesBane.dds`, `FightersBane.dds`, `ThiefsBane.dds`) were generated usingAI text-to-image tools (https://perchance.org/ai-text-to-image-generator) and Google’sGemini Image Creator and edited/converted to the game’s `.dds` formatusing Paint.NET. They are not hand-drawn or sourced from ESO’s own artassets.## Diseases5 independent diseases any subset active simultaneously, each at its ownseverity tier (Mild / Moderate / Severe). Contraction chances are allplayer-adjustable in Settings.| Disease | Trigger | Trait | Tint ||—|—|—|—|| Frostbite | Sustained cold exposure (5 min) | Protection | Pale blue || Heatstroke | Sustained hot exposure (5 min) | Protection | Warm orange || Mage’s Bane | Taking Magic/Fire/Cold/Shock damage (chance per hit) | Restore Magicka | Purple || Fighter’s Bane | Taking Physical damage (chance per hit) | Restore Health | Bruised red || Thief’s Bane | Taking Poison/Disease damage (chance per hit) | Restore Stamina | Sickly yellow-green |### Two trigger mechanisms**Frostbite and Heatstroke** use sustained exposure: once the player’seffective temperature (Frostfall-preferred, LibZoneTemp-fallback see`Calculator.GetCurrentTemperature()`) has sat outside the comfort bandcontinuously for 5 minutes, the disease becomes possible and re-rolls every60 seconds for as long as the exposure continues, until contracted or theplayer leaves the trigger range. Settings caps these 050% per roll.**Mage’s Bane, Fighter’s Bane, and Thief’s Bane** are each rolled on aqualifying hit of real typed combat damage instead no exposure timer.`Disease.lua` checks `damageType` on `EVENT_COMBAT_EVENT` against a`DAMAGE_TYPE_TO_DISEASES` lookup (Magic/Fire/Cold/Shock → Mage’s Bane,Physical → Fighter’s Bane, Poison/Disease → Thief’s Bane) the game’s ownreal damage-type classification for the hit, not a name-keyword guess.Since combat damage can land far more often than the exposure re-rollinterval, Settings caps these much lower: 010% per hit, in 0.5% steps.⚠️ The combat event’s parameter order and several of these `DAMAGE_TYPE_*`constants are unverified against a live client see in-code comments and`/rnd debug combat on`.### Curing: real ingredients, sourced from UESPEach disease is cured by raw alchemy **ingredients** (never potions), and**each disease has its own distinct trait** with 3 tiers of real,UESP-verified ingredients (common → rare):| Disease | Trait | Tier 1 | Tier 2 | Tier 3 ||—|—|—|—|—|| Frostbite | Protection | Mudcrab Chitin | Beetle Scuttle | Vile Coagulant *or* Powdered Mother of Pearl || Heatstroke | Protection | Mudcrab Chitin | Beetle Scuttle | Vile Coagulant *or* Powdered Mother of Pearl || Mage’s Bane | Restore Magicka | Corn Flower | Lady’s Smock | Vile Coagulant (Harrowstorms) || Fighter’s Bane | Restore Health | Mountain Flower | Water Hyacinth | Crimson Nirnroot (Blackreach) || Thief’s Bane | Restore Stamina | Blessed Thistle | Chaurus Egg | Dragon’s Blood (Dragons) |A tier-N ingredient cures that disease at severity ≤ N (a rare ingredient canoverkill-cure a mild case; a common one can’t touch a severe case).**The ingredient names/traits/sources above are real, verified data fromUESP, and every `itemId` in `RealisticNeedsAndDiseases_Data.lua` has alreadybeen filled in from an in-game scan except Thief’s Bane’s tier-3 Dragon’sBlood**, which is still a placeholder (`150731`, UESP-sourced but not yetconfirmed against a real scan, since the player hasn’t had one to check).### Care-cure: an alternative path for stronger afflictionsInstead of needing the rare tier-matched ingredient outright, a Severe orModerate case can also be cured gradually: eating the disease’s **tier-1(cheapest) ingredient repeatedly while hunger, thirst, AND fatigue are allabove a threshold** (default 70/100, adjustable) builds “care-cure progress.”Once enough doses accumulate (default 5, adjustable), the disease downgradesone severity tier Severe → Moderate → Mild → cured resetting progresseach step. Slower and requires sustained good self-care, but only ever needsthe cheap ingredient. Check progress anytime with `/rnd checkneeds`.—## Status windowA Frostfall-style colored-text window same structural pattern asFrostfall’s own `TemperatureHUD.lua`: a draggable top-level window with atooltip-style backdrop, four label+value+status rows (HUNGER/THIRST/FATIGUE/DRUNKENNESS), each showing a large number colored on ared→yellow→green ramp, **plus the current band status message text**(e.g. “I’m hungry.”) underneath each number, colored the same as the number.A DISEASES section below lists each active disease’s name, severity, and atext color matching that disease’s overlay tint.*(This row layout is inherited directly from this developer’s own Frostfalladdon, not from RolePlayNeeds RolePlayNeeds’ actual UI is a set of smallper-meter icon windows, not labeled text rows. An earlier version of thisREADME incorrectly implied the row layout traced back to RolePlayNeeds; seethe correction in Credits above.)*- Drunkenness’s color ramp is inverted (high = red/bad, low = green/good) the only row where that’s the case.- Drag the window anywhere position persists across sessions (`sv.settings.statusBarPosition`), with a “Reset status window position” button in Settings if it ever ends up off-screen.- **Toggle the whole window on/off** via the “Show needs status window” checkbox in Settings.- The window resizes dynamically to fit however many diseases are currently active (0 to 5).—## Settings panelEverything below is adjustable without editing code:- Temperature-coupling on/off, hours-to-empty for each meter, restore amounts for food/drink/harvest/coffee, warning thresholds, status bar visibility.- Contraction chance per disease (the three combat-damage diseases Mage’s Bane, Fighter’s Bane, Thief’s Bane capped lower than Frostbite/ Heatstroke, reflecting how much more often a hit can land than an exposure re-roll).- Care-cure “well cared for” threshold and doses-required.- Per-category emote choice (dropdown, real account-aware enumeration see Feedback section below) and an overall emote enable/disable toggle.- Drunkenness gain-per-drink, threshold, unaided sober-up time, and resting sober-up multiplier.- Fatigue recovery thresholds for all three resting mechanics, plus the fade-to-black toggle.Debug/reset actions live in `/rnd debug` now, not Settings buttons seeSlash Commands below.—## Dependencies“`## DependsOn: LibAddonMenu-2.0>=43## OptionalDependsOn: Frostfall>=4 LibZoneTemp>=10“`—## Slash CommandsAll commands are unified under `/rnd`.| Command | Description ||—|—|| `/rnd checkneeds` | Prints current hunger/thirst/fatigue/drunkenness, active temperature source, and each active disease’s severity plus care-cure progress. || `/rnd debug` (no args) | Prints the full list of debug subcommands below. |### `/rnd debug` subcommands| Subcommand | What it does ||—|—|| `/rnd debug ingredients` | Scans your backpack (and bank, if open) for any item whose name matches one of the ingredient names recorded in `Data.lua`. For each match: prints the real `itemId`, applies it in-memory **for this session only**, and prints a ready-to-paste line for `Data.lua`. || `/rnd debug combat on` / `off` | Dumps raw `EVENT_COMBAT_EVENT` args to chat for hits taken, confirming parameter order and showing the real `damageType` flags when it matches `DAMAGE_TYPE_DISEASE`. || `/rnd debug loot on` / `off` | Dumps raw `EVENT_LOOT_RECEIVED` args to chat for everything looted/harvested, confirming parameter order and `itemId` position. || `/rnd debug disease <1-5> <0-3>` | Directly sets a disease’s severity for testing, bypassing normal contraction rolls entirely. Index: 1=Frostbite, 2=Heatstroke, 3=Mage’s Bane, 4=Fighter’s Bane, 5=Thief’s Bane. Severity 0 clears it. || `/rnd debug curedisease` | Clears every active disease. Does **not** touch needs. || `/rnd debug resetneeds` | Resets hunger/thirst/fatigue/drunkenness to full/sober. Does **not** touch diseases. || `/rnd debug emptyNeeds` | Inverse of `resetneeds` drops hunger/thirst/fatigue to 0 and drunkenness to 100 (its worst value), for quickly testing the recovery mechanics without waiting for real decay. Does **not** touch diseases. || `/rnd debug testemote ` | Immediately plays the currently-configured emote for that category, bypassing the tick timer for previewing your Settings choice. |(`/rnd debug curedisease` and `/rnd debug resetneeds` replace the previouscombined `/rnd debug cureall` split so you can clear one without affectingthe other. The previous `/realneeds` alias has also been removed; use`/rnd checkneeds`.)None of the debug subcommands run on their own; every one is opt-in.—## Feedback systemRestructured to **mirror Frostfall’s own hot/cold feedback architecture**(this project’s own prior work, reused the way the inventory-consumptionpattern was reused elsewhere) both the notification mechanism and theemote system are now built the same way Frostfall builds theirs, just withdifferent thresholds/categories/values.### Notifications `ZO_Alert`, not `CENTER_SCREEN_ANNOUNCE“CENTER_SCREEN_ANNOUNCE` is gone. Notifications now use`ZO_Alert(UI_ALERT_CATEGORY_ALERT, nil, text)` the exact call Frostfalluses for its own hot/cold messages, confirmed working in this project’s owncode already, not a best-effort guess.### Status bands 4 fixed bands per category, dividing 0-100 equallyAs of 0.9.0, each of hunger/thirst/fatigue/drunkenness has its own 4-bandstatus message system, with **every band transition (worsening orimproving) firing its own notification** closer to Frostfall’s actual8-band design than the earlier binary normal/critical version of this filewas. Bands are fixed quartiles of the 0-100 range not tied to anyadjustable threshold setting anymore (the old warning-threshold sliders aregone, superseded by this).| Band | Hunger (75-100 → 0-25) | Thirst | Fatigue | Drunkenness (0-25 → 75-100) ||—|—|—|—|—|| 1 (best) | “I’m stuffed!” | “My thirst is quenched!” | “I’m well rested!” | “I’m completely sober.” || 2 | “I could use a snack.” | “I’m a bit thirsty.” | “I could use a break.” | “I’m-*hic*-a bit tipsy.” || 3 | “I’m hungry.” | “I need a drink.” | “I’m tired, I should find a place to sleep.” | “I’m-*hic*-nah’ drunk, you-*hic*-you’re drunk!” || 4 (worst) | “I’m starving!” | “I’m dehydrated!” | “I’m exhausted! I might pass out soon!” | “WOOOOOO! I-*hic*-cannaht-*hic*-feel ma facsh!” |Bands 1-2 = value 50-100 (or 0-50 for drunkenness); bands 3-4 = the bottomhalf of badness. **Emotes only play at bands 3 and 4** bands 1-2 updatethe status window and fire notifications, but never trigger an emote.### Emotes real `PLAYER_EMOTE_MANAGER` enumeration, not guessed indices or hijacked commandsTwo designs ago this used guessed numeric `PlayEmoteByIndex` indices (mostlyunconfirmed). Last version switched to hijacking `SLASH_COMMANDS`strings. **This version replaces both** with the same real, confirmedmechanism Frostfall already uses:`PLAYER_EMOTE_MANAGER:GetEmoteListForType(category)` /`:GetEmoteItemInfo(emoteId)` to enumerate every emote the player actuallyowns (including personality-overridden variants), `FindEmoteIdByDisplayName`to resolve a default by name with a slash-name fallback, and`GetEmoteIndex(emoteId) → PlayEmoteByIndex(index)` to actually play it. Thisis the real, accountable sense of “use the game’s API to look up availableoptions” an enumeration call already proven to work in this project,not a filter over a hand-curated list.A dedicated, deterministic 20-second timer (Frostfall’s own equivalent runsevery 15 seconds deliberately different value here) checks each category’sband and plays its configured emote once it reaches band 3 or 4, gatedon `IsUnitInCombat`, `IsMounted`, and `IsAnyMajorUIOpen` same three guardsFrostfall’s `TickEmote` uses, no random chance roll anymore.| Category | Default emote | UESP description | Audio? ||—|—|—|—|| Hunger | **Angry** | “Throw your arms to the side and snarl” | No || Thirst | Breathless | “Hunch over with your hands on your knees and pant” | No || Fatigue | Yawn | “Stretch your arms and yawn” | **Yes** || Disease | Sickened | “Heave over and vomit” | No || Drunkenness | Drunk | “Teeter and reel in a drunken stupor” | No |Hunger and thirst have no literal match in ESO’s emote list closestthematic analogues, flagged honestly. Fatigue, disease, and drunkenness allhave genuine exact matches.⚠️ If you’d previously played an earlier version, your saved `hunger`emote choice may still be the old default (Headache) the new default(Angry) only applies automatically on a fresh save, since changing a*default* doesn’t retroactively overwrite a value you (or a previous default)already resolved. Reselect it in Settings if you want the new default.Events that notify (chat + `ZO_Alert`): every band transition forhunger/thirst/fatigue/drunkenness (not just entering/leaving one criticalthreshold anymore), disease contraction/escalation, both cure paths.Harvest-restores-thirst, alcohol, and coffee messages stay chat-onlydeliberately (frequent actions; an alert every time would be noisy).—## Drunkenness (new)Drinking an alcoholic beverage (detected by name keyword mead, ale, wine,rum, rotmeth, sujamma, etc., same honest name-heuristic limitation as the undead-damagekeyword list used previously) builds up drunkenness (default +15/drink,adjustable). Unlike hunger/thirst/fatigue, **high drunkenness is the badstate**, not low.- Decays on its own over time (default: fully sober in ~2 hours unaided).- **Resting accelerates sobering up** (default 4x faster) any of the three fatigue-recovery mechanics below (standing still, sitting, sleeping) also reduces drunkenness while active.- The status window’s color ramp is inverted for this row specifically (high = red/bad, low = green/good) everywhere else, high = good.—## Coffee (new explicitly the user’s own idea, not adapted from any third-party addon)Drinking coffee (detected by name keyword: coffee, joe, espresso) restoresfatigue (+25 default, adjustable) **in addition to** the normal thirstrestore every drink already gives. Built fresh for this addon sameinventory-consumption-detection pattern used everywhere else here, notborrowed implementation from any other addon.—## Fatigue recoveryThree mechanics, all gated on **not moving and being out of combat** (yourown position/combat state only reading your own state is allowed; therestriction is on reading *other* units’ positions):1. **Standing still** for several minutes (default 3, adjustable) → slow passive regen.2. **Sitting** (any `/sit` variant, `/sitchair`, or interacting with a real in-world chair/bench) for about a minute (default 60s, adjustable) → faster regen than just standing.3. **Sleeping/meditating** for a while (default 60s, adjustable) → full restore, with an optional fade-to-black/fade-back screen effect simulating the passage of time.All three also accelerate drunkenness decay while active (see Drunkenness above).For mechanic 3: `/sleep`, `/sleep2`, and `/faint` are real sleep-pose emotes.**ESO has no literal “/meditate” emote** `/pray` and `/kneelpray` are usedas the closest thematic stand-ins, flagged honestly rather than implying areal meditate animation exists.Detection works by **hooking** the relevant slash commands (preserving theiroriginal behavior, then tracking state alongside) rather than polling some”is the player sitting/sleeping” state query I don’t have confidentknowledge of such a query existing, so instrumenting the actions we alreadyknow are real (confirmed via UESP) is the more honest mechanism.Sitting is *also* detected when the player interacts with a real in-worldobject whose reticle prompt reads “Sit” (a placeable chair, a bench, etc.),independent of and in addition to the `/sit`-family slash-command hookingabove. This reads the reticle’s interaction text via`GetGameCameraInteractableActionInfo()` (the same technique the NoInteractaddon, by Rhyono, uses for reading reticle state) and uses the moment`INTERACTIVE_WHEEL_MANAGER.StartInteraction` fires which happens on everysingle interact keypress, confirmed via the current ESOUI source’s`GAME_CAMERA_INTERACT` keybind definition as the trigger. This went throughtwo wrong turns before landing here: first hooking `FISHING_MANAGER.StartInteraction` (following NoInteract’s own code too literally broke onload once ZOS removed the standalone `FishingManager` class, and was neveractually correct even before that, since that function only ever dispatchedto the fishing radial-wheel UI), then hooking the bare global`GameCameraInteractStart()` directly (broke because that function isgenuinely protected no addon can even read it, per the actualin-game error). `INTERACTIVE_WHEEL_MANAGER` is the unprotected, still-existingLua object that replaced `FISHING_MANAGER`, and its `:StartInteraction`method is exactly the modern equivalent of what NoInteract’s hook wasreaching for. See `Rest.lua`’s `HookWorldInteractionDetection`.There is no RND-specific `/rnd sit` or `/rnd sleep` command anymore bothwere removed once native command hooking and world-interaction detectionwere confirmed reliable enough to cover sitting/sleeping on their own.Just sit or sleep normally; RND detects it.Entering rest mode via sitting or sleeping prints a chat-only confirmation(“You take a seat to rest.” / “You settle in to sleep.”) regardless of whichof the three detection paths triggered it the `/sit`-/`/sleep`-familyslash-command hooks, the world-object interaction hook, or (in principle)any future path, since the message lives in `Rest.lua`’s shared`OnSitTriggered`/`OnSleepTriggered` rather than being duplicated at eachhook site. It only fires on the actual transition into that pose, not onevery re-trigger while already seated/sleeping, so repeatedly interactingwith the same chair doesn’t spam chat.The fade-to-black overlay reuses the same generic top-level-window patternalready used for disease overlays, manually stepping alpha up then down via`EVENT_MANAGER:RegisterForUpdate` (no `ZO_AlphaAnimation`/animation-managerAPI assumed, since I didn’t have confident knowledge of that API’s exactshape either).—## Known gaps- **Dragon’s Blood (Thief’s Bane tier 3)** is the only remaining unconfirmed ingredient itemId wasn’t in the player’s last scan. Run `/rnd debug ingredients` again once you have one.- Some of Mage’s Bane’s damage-type triggers (Fire/Cold/Shock) are believed-real but individually unconfirmed against a live client resolved defensively (skipped with a chat warning, not a crash, if any turn out wrong). `DAMAGE_TYPE_MAGIC` was already confirmed elsewhere in this project.- Combat event parameter order unverified; loot event parameter order unverified; `DAMAGE_TYPE_DISEASE` constant unverified `/rnd debug combat on` / `loot on` will confirm these.- **`EVENT_POWER_UPDATE`’s parameter order is unverified** (the new stamina-exertion mechanic) `/rnd debug power on` will confirm.- **`LibFoodDrinkBuff` is now a required dependency**, using its real confirmed `IsAbilityAFoodOrDrinkBuff(abilityId)` method (found by inspecting a real working usage, not guessed) as a consumption-confirmation gate. `/rnd debug libcheck` still exists for double-checking the method exists in your installed version.- **Native command hooking for `/sit`/`/sleep` is confirmed reliable**, not just assumed: the current ESOUI source shows ZOS’s own `PLAYER_EMOTE_MANAGER` registers every native emote (including `/sit`, `/sleep`, `/sitchair`, etc.) into this exact same addon-visible `SLASH_COMMANDS` table itself. `/rnd sleep` and `/rnd sit` were removed once this, plus the world-object interaction hook below, were confirmed reliable enough to cover sitting/sleeping without an explicit command. If a future ESO client ever stops routing these through `SLASH_COMMANDS`, this path would silently stop working with no explicit-command fallback; worth keeping an eye on across major game updates.- **World-object “Sit” interaction detection hooks `INTERACTIVE_WHEEL_MANAGER.StartInteraction`**, confirmed via the current ESOUI source’s `GAME_CAMERA_INTERACT` keybind definition to fire on every interact keypress. This took two wrong attempts to get right: `FISHING_MANAGER.StartInteraction` (copying NoInteract’s code too literally broke on load once ZOS removed the standalone `FishingManager` class, and was never actually correct even before that), then the bare global `GameCameraInteractStart()` directly (broke because it’s a genuinely protected engine function no addon can access). `INTERACTIVE_WHEEL_MANAGER` is the unprotected object that replaced `FISHING_MANAGER`. The reticle-text word-match currently only actually fires on “Sit”; “Sleep” is wired up defensively in case a bed-type interactable ever uses that exact prompt, but that hasn’t been observed in-game.- The fade-to-black overlay’s manual alpha-stepping is untested in a live client.- “/pray” and “/kneelpray” are thematic stand-ins for “meditate,” which has no real ESO emote.- Alcohol and coffee detection are both name-keyword heuristics will miss any drink whose name doesn’t contain a listed keyword; expand `RN.ALCOHOL_KEYWORDS`/`RN.COFFEE_KEYWORDS` in `Data.lua` as needed.- The exertion-reference constant (300 stamina/tick for max multiplier) and the emote interval range (5-25s) are both first-draft tuning values, not playtested.—## Changelog### 0.19.5- **Corrected a misattribution to RolePlayNeeds**, verified against the official published v0.7 BETA release (the developer supplied the actual release zip for comparison). Three things previously credited to RolePlayNeeds in the README’s Credits section, and referenced as RPN-verified in code comments, do not exist in RolePlayNeeds’ real published source they were additions made to a local, personally- modified copy of RolePlayNeeds, not the published addon: – A `RPN_REAGENT_TRAITS` alchemy-trait lookup table (no such table, and no “reagent” string at all, appears anywhere in RolePlayNeeds’ source). – A “two-stage” water-loot detection fix (RolePlayNeeds’ actual `EVENT_LOOT_RECEIVED` handler is single-stage, with no inventory-update confirmation step). – A labeled-row HUD/window layout (RolePlayNeeds’ real UI is a set of small per-meter icon windows, structurally nothing like this addon’s or Frostfall’s label+value+status row layout). – Two credits were confirmed genuinely accurate and are kept: the `bindings.xml`/keybind naming convention, and the inventory-seed-on- login fix (`ForceInventoryScan()` on `EVENT_PLAYER_ACTIVATED`). – Corrected the affected code comments in `RealisticNeedsAndDiseases_Data.lua` (Mage’s Bane’s ingredient-sourcing note, which also named the wrong ingredients Fighter’s Bane’s set, not Mage’s Bane’s own) and `RealisticNeedsAndDiseases.lua` (the water-loot detection note) to stop claiming RPN corroboration for data that was never actually corroborated against it.### 0.19.4- **Corrected the README’s “Diseases” section, which still described the disease roster from before the 0.14.00.16.0 overhaul** (Bone Chill, Swamp Rot, Ashen Cough, Blood Fever, Wormwood Plague all since renamed, redesigned, or removed) instead of the current 5: Frostbite, Heatstroke, Mage’s Bane, Fighter’s Bane, Thief’s Bane. Also fixed: – The overview paragraph’s disease count (“6 independently-trackable” → “5”) and the manifest’s `## Description` (“7 diseases” → “5”). – The trigger/trait/ingredient tables, rewritten to match `RealisticNeedsAndDiseases_Data.lua`’s actual current definitions, including the two real trigger mechanisms (sustained exposure for Frostbite/Heatstroke vs. per-hit damage-type for the other three) and their real Settings-panel chance caps (050% vs. 010%). – The “only itemId is unverified” claim, which was stale now that nearly every ingredient has a real in-game-scanned `itemId` only Thief’s Bane’s tier-3 Dragon’s Blood is still unconfirmed. – The `/rnd debug disease <1-5>` index labels, the “Known gaps” section’s Ashen-Cough-specific bullets, the Settings-panel summary’s Wormwood Plague reference, and a leftover `/realneeds` mention (the alias was removed in an earlier version replaced with `/rnd checkneeds`). – This section (and the changelog entries below it) is a historical record and intentionally left describing the old names as they existed at the time.### 0.19.3- **Fixed the settings panel’s author field**, which still read the older `”Krek (@Kreksar5)”` form rather than the now-standardized `”@Kreksar5 and Claude.ai”`. The panel’s `version` field already read from `RN.VERSION` correctly; that constant is bumped alongside the manifest going forward.### 0.19.2- **Expanded the “Overlay art credit” note** for the disease status-overlay images to also credit Google’s Gemini Image Creator (alongside the Perchance AI Text-to-Image Generator) for generation, and Paint.NET for editing/converting them to the game’s `.dds` format.### 0.19.1- **Standardized the author credit** to `@Kreksar5 and Claude.ai` in the `## Author` manifest field and this README’s byline, and named Claude.ai specifically (rather than generic “AI assistance”) in the manifest description and the AI-assistance disclosure above, matching the crediting convention used across this addon’s companion libraries.### 0.19.0- **Added a standalone “Enable the disease system” toggle** in Settings, next to the disease contraction-chance sliders. Independent of the existing master “Enable the needs/disease system” switch: turning this off stops all new disease contraction and severity escalation (both the sustained cold/ heat exposure path and the combat-damage path funnel through the same `RollContraction` choke point in `RealisticNeedsAndDiseases_Disease.lua`, so gating it there covers both with one check) while leaving hunger, thirst, fatigue, and drunkenness decaying/restoring exactly as normal. Curing an already-active disease still works while this is off. Disease overlay tints clear the moment this is switched off and reappear at their correct severity when switched back on, mirroring how the master switch already handles overlays. The `/rnd status` (`/rnd`) command now also notes when the disease system specifically is off (separate from the existing note for the master switch).- **Fixed `RN.VERSION` being stuck at `”0.18.0″`** in `RealisticNeedsAndDiseases.lua` it hadn’t tracked the manifest’s `## Version` since 0.18.1, so `/rnd status` and the settings panel’s displayed version were both quietly stale. Now synced to match the manifest.### 0.18.9- **Added the required `## AddOnVersion` tag** (previously missing entirely this is the integer the ingame addon manager and Minion use to detect updates, separate from the informational `## Version` tag). Started at 9.- **Added a version floor (`>=19`) to the `LibFoodDrinkBuff` dependency**, which previously had none.- **Bumped the optional `LibZoneTemp` dependency floor** from `>=10` to `>=12`, matching LibZoneTemp’s current `## AddOnVersion`.- **Added the AI-assistance disclosure to the manifest description** (it was already present in this README, but not in the manifest’s `## Description`, which is what Minion shows at a glance).- **Added a Credits section** naming RolePlayNeeds (matheusbk2) and No Interact (Rhyono) for the implementation techniques referenced during development.### 0.18.8- **Full API audit against the official ESOUI API 101050 documentation.** Every function call, method call, and constant referenced across the addon was cross-checked against the API doc and, where the doc didn’t cover it (manager singletons, `ZO_` helpers, third-party libraries), against the live ESOUI source.- **Fixed a nonexistent constant in the combat-event filter**: `REGISTER_FILTER_TARGET_TYPE` does not exist anywhere in the ESO API and would have errored registering the disease-contraction combat-event filter. Corrected to `REGISTER_FILTER_TARGET_COMBAT_UNIT_TYPE`, the real constant (confirmed against both the API doc and live ESOUI usage).- Everything else checked out: `EVENT_MANAGER`, `SCENE_MANAGER`, `PLAYER_EMOTE_MANAGER`, `RETICLE`, `INTERACTIVE_WHEEL_MANAGER`, `ZO_Alert`, `ZO_PreHook`, `ZO_CreateStringId`, and the `LibFoodDrinkBuff`/ `LibAddonMenu`/`LibSavedVars` calls are all legitimate and correctly used.### 0.18.7- **Added `/rnd debug emptyNeeds`** the inverse of the existing `/rnd debug resetneeds`: drops hunger/thirst/fatigue to 0 and drunkenness to 100 (its worst value, since high drunkenness is the bad state), for quickly reaching a state where the recovery mechanics actually have something to recover without waiting for real decay. Doesn’t touch diseases, same as `resetneeds`.- **Sitting/sleeping now prints a chat-only confirmation on entering rest mode** (“You take a seat to rest.” / “You settle in to sleep.”), restoring feedback that existed under the old `/rnd sit`/`/rnd sleep` commands but had gone silent once those commands were removed in favor of automatic detection. Added at the single shared point (`OnSitTriggered`/ `OnSleepTriggered` in `Rest.lua`) that every detection path funnels through, so it fires the same way regardless of which path triggered it, and only on the actual transition into that pose not on every re-trigger while already resting, to avoid spamming chat.### 0.18.6- **Further expanded the sit-recognition word list** with more synonyms for “an object you sit on”: “stool”, “pew”, “throne”, “couch”, “sofa”, “settee”, “loveseat”, “ottoman”, “stump”, “log” (alongside the existing “sit”, “seat”, “chair”, “bench”). Only “Sit” and “Chair” have actually been observed in-game; the rest are speculative/defensive the same way “Sleep” already was harmless if they never match anything real.### 0.18.5- **Expanded the world-object sit-recognition word list** from just “Sit” to “Sit”, “Seat”, “Chair”, “Bench”. Also widened what gets checked against that list: previously only the reticle’s action verb was captured; now the interactable’s own name (e.g. “Wooden Chair”, “Tavern Bench”) is captured alongside it and both are checked together, since “Chair”/”Bench” are realistically going to appear in an object’s name rather than in the verb.### 0.18.4- **Fixed the world-object “Sit” interaction detection silently never firing.** No crash this time the addon loaded fine, but interacting with a real chair never engaged fatigue tracking or the emote-interruption protection, even though the fix in 0.18.3 resolved the load errors. Root cause: `GetGameCameraInteractableActionInfo()` returns `(action, interactableName, …)` the reticle prompt’s *verb* (“Sit”, “Loot”, “Talk to”) is the FIRST value, and the target’s own display name (“Wooden Chair”, an NPC’s name, etc.) is the SECOND. The code was doing `local _, text = GetGameCameraInteractableActionInfo()`, which discards “action” and keeps “interactableName” copied directly from NoInteract’s own destructuring without noticing NoInteract wants `interactableName` for ITS purpose (matching NPC/object names against a blacklist), the opposite of what this addon needs (matching the action verb “Sit”). Since object display names essentially never contain the literal word “sit”, the word-match silently never matched anything. Fixed to read `action` (the first return value) instead.### 0.18.3- **Fixed a second load-time crash**: `Attempt to access a private function ‘GameCameraInteractStart’ from insecure code`. 0.18.2’s fix for the previous crash had reassigned the bare global `GameCameraInteractStart`, reasoning it was the function the interact keybind calls true, but it turns out to be a genuinely protected engine function that addons cannot even read, let alone override. Traced the actual current keybind chain in ESOUI’s `bindings.xml`: `if not INTERACTIVE_WHEEL_MANAGER:StartInteraction(ZO_INTERACTIVE_WHEEL_TYPE_FISHING) then GameCameraInteractStart() end` `INTERACTIVE_WHEEL_MANAGER` is a plain, unprotected Lua object (the direct successor to the now-removed `FISHING_MANAGER`), and its `:StartInteraction` method fires on every single interact keypress before the engine ever considers falling through to the protected call. Hooked that instead same reassign-and-preserve-original pattern NoInteract uses, just pointed at the object that actually exists and is actually reachable in the current client.### 0.18.2- **Fixed a load-time crash** (`attempt to index a nil value` in `HookWorldInteractionDetection`) caused by 0.18.1’s world-object interaction hook reassigning `FISHING_MANAGER.StartInteraction` ZOS has removed the standalone `FishingManager` class from the current client, so that global no longer exists at all. Root cause went deeper than a missing nil-check, though: pulling the current ESOUI source (github.com/esoui/esoui) confirmed that function was never actually the right hook for this even when it did exist `FISHING_MANAGER:StartInteraction()` only ever dispatched to the fishing radial-wheel UI, so it would never have fired for a chair’s “Sit” prompt regardless. Replaced with a hook on the bare global `GameCameraInteractStart()`, confirmed via `esoui/ingame/globals/bindings.xml`’s `GAME_CAMERA_INTERACT` keybind definition to be exactly what the interact key invokes for ordinary (non-fishing-wheel) interactions. Also upgraded the native `/sit`/`/sleep` slash-command hooking from “assumed reliable” to confirmed: the current source shows ZOS’s own `PLAYER_EMOTE_MANAGER` registers those commands into the same addon-visible `SLASH_COMMANDS` table this addon hooks.### 0.18.1- **Added world-object interaction detection for sitting.** Interacting with a real in-world chair/bench (reticle prompt “Sit”) now starts the same fatigue-recovery/emote-interruption-protection tracking as `/rnd sit` used to, without needing any slash command at all. Modeled on the NoInteract addon’s (by Rhyono) two-hook reticle-interaction pattern: `ZO_PreHook` on `RETICLE:TryHandlingInteraction` to read the current prompt text via `GetGameCameraInteractableActionInfo()`, and wrapping `FISHING_MANAGER.StartInteraction` (original preserved, always called) as the point where the interaction is actually confirmed. RND never blocks the interaction only observes it. Matching is whole-word (not substring), so prompts like “Deposit” or “Visit” can’t false-positive against “Sit”. See `Rest.lua`’s `HookWorldInteractionDetection`.- **Removed `/rnd sleep` and `/rnd sit`.** Now that native `/sit`-/`/sleep`- family command hooking and the new world-object interaction detection both reliably start rest tracking on their own, the explicit commands (which existed specifically to *guarantee* tracking started, back when the native-command hook’s reliability was still uncertain) are obsolete. Sitting/sleeping normally by any means now triggers fatigue recovery and emote-interruption protection automatically; `Rest.TriggerSit()` / `Rest.TriggerSleep()` are removed along with the commands.- **Removed the `sleepPose`/`sitPose` configurable-emote settings.** These existed only to let `/rnd sleep`/`/rnd sit` play a player-chosen emote for that category; with those commands gone there’s no remaining code path that plays a “configured” sit/sleep emote whatever the player actually does (which real emote, which chair) is simply the emote. Removed from `Feedback.EMOTE_DISPLAY_DEFAULTS`/`EMOTE_SLASH_FALLBACKS`/ `EmoteIds`, the Settings emote dropdown list, `emoteChoiceId` defaults, and `/rnd debug testemote`’s category list.### 0.17.2- **Fixed Frostfall version gate in manifest** `OptionalDependsOn` was declaring `Frostfall>=4`, which caused ESO’s addon loader to treat Frostfall as absent even when v3.x (including v3.4.4) was installed. RND then fell back to LibZoneTemp’s raw ambient zone temperature for all temperature checks, silently bypassing Frostfall’s insulation, weather/precipitation, swimming drag, and spell-resist reagent buff. Changed to `Frostfall>=3` so the 3.x series is correctly recognized.- **No code changes required** `Calculator.GetCurrentTemperature()` already called `Frostfall:GetEffectiveTemp()` (not `GetZoneAmbientTemp()`) when Frostfall was present, which is the correct value: the player’s physical temperature after insulation/weather/swimming drift, plus any active spell-resist reagent offset. All hunger/thirst/fatigue decay acceleration and frostbite/heatstroke exposure checks therefore already used effective temperature the manifest gate was the only thing preventing them from doing so when Frostfall 3.x is installed.- Expanded the `GetCurrentTemperature()` comment block in Calculator.lua to document what `GetEffectiveTemp()` includes, and added a note explaining the manifest version gate and what happens if it fails.- **Reduced Frostbite/Heatstroke’s initial exposure threshold from 10 minutes to 5 minutes**, per request `Disease.EXPOSURE_THRESHOLD_SECONDS` is now `300` instead of `600`. The first contraction roll now happens after 5 minutes of continuous qualifying exposure instead of 10; the 60s re-roll interval after that threshold (0.17.0) is unchanged. Updated the matching comments in Data.lua, Disease.lua, and the main file, and the Settings panel’s description text, so nothing still says “10 minutes.”### 0.17.0- **Corrected misunderstanding from 0.16.0**: Frostbite/Heatstroke’s contraction check now actually REPEATS every 60s once the initial 600s exposure threshold is met, for as long as the player stays in the qualifying temperature range it doesn’t just roll once and then wait out another full 600s. 0.16.0’s “verification” confirmed the OLD single-roll-per-threshold-crossing behavior was internally consistent, but that behavior itself was wrong per what was actually wanted here; this is the real fix. – `CheckSustainedCold`/`CheckSustainedHeat` are now both thin wrappers around a new shared `CheckSustainedExposure` helper in Disease.lua. Exposure time keeps accumulating past the 600s threshold (it no longer resets at that point); once past it, a second timer (`rollTimerSeconds`, new) ticks up and fires a contraction roll every `Disease.EXPOSURE_REROLL_INTERVAL_SECONDS` (60s, new constant). – It stops repeating the instant EITHER stated condition is met: the disease is contracted (`sv.diseaseState` becomes non-nil checked every tick before rolling, so it can’t roll once more after contracting), or the player leaves the qualifying temperature range (both timers reset to 0 immediately, so re-entering starts the full 600s wait over from scratch, not a resumed countdown). – If a roll succeeds, the long 600s exposure timer is ALSO reset at that moment (on top of the disease now blocking further rolls) so if this case gets cured later while the player is still standing in the same cold/heat, it requires a full fresh 600s wait before anything can roll again, rather than immediately resuming 60s re-rolls right after a cure. – Sandbox-simulated 30 minutes of continuous exposure to confirm this behaves as intended: first roll at 660s (600s wait + first 60s interval), further rolls roughly every 60s after that, stopping immediately on contraction; also confirmed leaving exposure zeroes both timers. – `/rnd debug frostbiteTimer`/`heatstrokeTimer` (0.16.0) updated to match: they now report which of three states you’re in not yet at the initial threshold, past it and actively re-rolling every 60s, or already contracted and not currently rolling at all rather than a single elapsed/remaining number that no longer matched the real mechanic. `Disease.GetSustainedExposureStatus` now also takes `sv` (to check whether the disease is already active) and reports `pastThreshold`/`contracted`/`rerollIntervalSeconds`/`rollTimerSeconds` alongside the original fields.### 0.16.0- **Verified, by direct code inspection: Frostbite/Heatstroke’s contraction check does NOT fire repeatedly after the threshold is met.** In both `CheckSustainedCold` and `CheckSustainedHeat`, the exposure counter is reset to 0 in the SAME branch that calls `RollContraction`, immediately before the roll so once the threshold crosses, the very next tick starts accumulating from 0 again, and a full new `EXPOSURE_THRESHOLD_SECONDS` (600s) must elapse before the next roll. The contraction check fires exactly once per threshold-crossing, not on every later tick spent still standing in the cold/heat past the threshold. No code change was needed here this was a read of the existing logic, confirming it was already correct.- **Added `/rnd debug frostbiteTimer` and `/rnd debug heatstrokeTimer`.** Each prints whether you’re currently in the qualifying temperature range, the current temperature, elapsed/threshold exposure seconds, time remaining until the next contraction roll, and the dice-roll chance that roll will actually succeed (`sv.settings.diseaseChances.`). Backed by a new `Disease.GetSustainedExposureStatus(kind)` accessor (`kind` is `”cold”` or `”heat”`) that reads the exact same `exposureSeconds` counter `CheckSustainedCold`/`CheckSustainedHeat` themselves use this is a read-only view of the real running state, not a separate estimate that could drift out of sync with it. If you’re not currently exposed, it says so rather than printing a stale or misleading countdown (the real counter resets to 0 the instant you leave the trigger range, so there’s nothing counting down until you re-enter it).### 0.15.0- **Ashen Lung removed completely, per request** (0.14.0/0.14.1/0.14.2’s disable-but-keep-the-code approach is gone this isn’t a deeper hide, it’s an actual deletion): – Removed from `RN.DISEASE_ORDER` and `RN.Diseases` (Data.lua) its disease definition, cure ingredients, and flavor text no longer exist anywhere. – Removed `RN.ASHEN_LUNG_EXCLUDED_HOUSES` (the ~100-entry player-house list) entirely it had no other purpose. – Removed `Disease.CheckVolcanicHeatExposure`, its call in `Disease.OnTick`, and its three constants (`VOLCANIC_HEAT_THRESHOLD_CELSIUS`, `VOLCANIC_EXPOSURE_THRESHOLD_SECONDS`, and the `volcanicHeatExposure` exposure-timer entry) from Disease.lua. – Removed `Calculator.GetCurrentZoneName()` it existed solely to support Ashen Lung’s house-exclusion check and had no other callers. – Removed the whole `Disease.ASHEN_LUNG_ENABLED`/`Disease.IsDiseaseEnabled` disable-switch mechanism added in 0.14.00.14.2 it existed specifically to hide Ashen Lung without deleting it; now that it’s actually deleted, the indirection has nothing left to gate. Settings.lua, DebugHelper.lua, and the main file’s `/rnd debug` usage builder are all reverted to their simpler pre-0.14.0 forms (just without Ashen Lung). – `RN.DISEASE_ORDER` is now `{ frostbite, heatstroke, bloodworms, mageBane, fightersBane, thiefsBane }` 6 entries. `/rnd debug disease <1-6>`; index 3 (Ashen Lung’s old slot) is gone rather than left as a gap, since there’s no longer any reason to preserve a hole for a disease that no longer exists at all. – Removed `textures/overlays/AshenLung.dds` from the package. – Thief’s Bane keeps its Restore Stamina ingredient set (Blessed Thistle / Chaurus Egg / Dragon’s Blood) it was always its own copy of the data, just originally commented as “shared with Ashen Lung.” That comment is now corrected; the ingredients/itemIds themselves are unchanged.- **Found and fixed the actual cause of the sleep/sit-pose emote interrupt** (0.13.0’s gating logic was correct but insufficient this is the real fix). Root cause: `Rest.lua`’s movement detection used a single 5-world- unit tolerance (`POSITION_EPSILON`) for two very different purposes (a) detecting “stood still long enough to regen” and (b) detecting “got up out of the sit/sleep pose.” The pose-transition animation itself (and likely ongoing idle sway while held) plausibly shifts the tracked root position by more than 5 units within a single 5-second tick on its own, which was flipping `_isSeated`/`_isSleeping` back to `false` within roughly one tick of being set re-opening `CanPlayEmotesNow`’s gate and letting a status emote fire (and visibly cancel the pose) only seconds into `/rnd sleep` or `/rnd sit`, even though the emote-gating logic itself was working exactly as designed. – Added a separate, much more lenient `REST_POSITION_EPSILON` (150 world units) used only while `_isSeated`/`_isSleeping` is already true; `POSITION_EPSILON` (5) still governs the idle-standing regen mechanic unchanged. – `OnSitTriggered`/`OnSleepTriggered` now reset the position baseline (`_lastPosition = nil`) at the moment a pose starts, so the settle-into-pose position shift itself is never compared against a pre-pose baseline at all eliminating the original one-tick race on top of widening the ongoing tolerance. – **Honesty note**: 150 is a deliberately generous guess, NOT measured against real in-client position deltas during a sleep/sit pose. If interruptions still happen after this, the right next step is logging the actual per-tick `distSq` while seated/sleeping and raising this further to match say so and I’ll add a temporary debug print for it.### 0.14.2- **Scrubbed Ashen Lung from the debug surface too, per request** (0.14.1 deliberately left this alone; now fully hidden there as well): – `/rnd debug` ‘s help text now builds its disease-index line dynamically from `RN.DISEASE_ORDER`/`RN.Disease.IsDiseaseEnabled` instead of a hardcoded string a disabled disease’s name never prints, and its index number is simply skipped (the list jumps 1, 2, 4, 5…) rather than relabeling every later index, since index positions are meant to stay stable/permanent (see Data.lua’s own comment on `DISEASE_ORDER`). – `/rnd debug disease 3 ` now returns the exact same generic “Invalid disease index” message a genuinely out-of-range index would so probing index numbers by hand can’t distinguish “doesn’t exist” from “exists but disabled.” – `/rnd debug ingredients` had a separate leak: Ashen Lung shares its exact ingredient set with Thief’s Bane, so scanning Blessed Thistle/ Chaurus Egg/Dragon’s Blood was printing an “applied to Ashen Lung tier N” line right alongside the Thief’s Bane one. The ingredient name index it scans against is now built only from enabled diseases. – All of this still routes through the same single `Disease.IsDiseaseEnabled` switch added in 0.14.1 re-enabling Ashen Lung restores it everywhere (Settings, Healer’s Guide, AND now the debug surface) with that one flag, no separate debug-side toggle to remember.### 0.14.1- **Clarified per request: Ashen Lung being “disabled” means invisible to the player, not just inert.** 0.14.0’s greyed-out Settings slider and unchanged Healer’s Guide entry still told the player it existed fixed: – New `Disease.IsDiseaseEnabled(diseaseId)` in Disease.lua, a single centralized check (currently just `diseaseId == “ashenLung”` gated on `Disease.ASHEN_LUNG_ENABLED`) used everywhere a disease might be shown in the UI, so future per-disease disables only need one new line here rather than hunting down every display call site again. – Settings panel’s chance-slider loop now skips disabled diseases entirely (no slider rendered at all, not greyed out) and the disease-chances description text no longer mentions Ashen Lung by name, since that text alone would have told the player it exists even with no slider. – The Healer’s Guide loop (built from `RN.DISEASE_ORDER`) now also skips disabled diseases no header, flavor text, or cure-ingredient lines for Ashen Lung while it’s off. – **Still NOT hidden, by design**: `/rnd debug disease 3 ` and the `/rnd debug` help text still reference Ashen Lung by name. That’s a developer-only debug command, not a normal player-facing surface if you’d also like it scrubbed from there, say so and I’ll do it, but I didn’t want to take away your own ability to force-test a disabled disease without being asked. – Data.lua’s definition, the overlay window (created at load for every disease but only ever shown if `Overlay.RefreshDisease` is called, which natural contraction can no longer trigger), and the asset file are all still fully intact, per “disable, don’t remove.”### 0.14.0- **Ashen Lung’s natural contraction trigger is now disabled, per request** disease definition, Healer’s Guide entry, overlay (now `AshenLung.dds`, unchanged), and `/rnd debug disease 3 ` index slot are all left fully intact; only `Disease.CheckVolcanicHeatExposure` is switched off, gated by a new `Disease.ASHEN_LUNG_ENABLED = false` constant in Disease.lua. While disabled, its exposure timer stays pinned at 0 and the disease can never roll naturally from standing in extreme heat `/rnd debug disease 3 ` can still force it directly for testing, and any case already active before this was disabled still progresses/cures normally (this only blocks NEW natural contraction). Flip the constant back to `true` to re-enable.- Settings panel’s Ashen Lung chance slider is now greyed out (`disabled` field see the UNVERIFIED-AGAINST-LAM-SOURCE caveat in Settings.lua; worst case if it doesn’t visually grey out, the slider is still functionally inert) with an explanatory tooltip, and its label/the disease-chances description text both updated to say so, rather than silently offering a control that does nothing.- Also fixed two stale wording leftovers from 0.13.x while touching this file: Mage’s Bane’s Settings label and description said “frost” instead of the corrected “cold” (matching 0.13.2’s `DAMAGE_TYPE_COLD` fix), and Fighter’s Bane’s label still mentioned “bleed” despite 0.13.2 dropping that trigger entirely.### 0.13.2 hotfix- **Fixed a load-time crash**: `RealisticNeedsAndDiseases_Disease.lua:324: table index is nil`. 0.13.1’s `DAMAGE_TYPE_TO_DISEASES` table used `DAMAGE_TYPE_FROST` as a literal table key but that global doesn’t exist in ESO’s API (the real constant is `DAMAGE_TYPE_COLD`; “Frost Damage” is UI flavor text, the engine kept the older “Cold” name). A nonexistent global evaluates to `nil`, and Lua refuses `nil` as a table key in a literal constructor, which failed the whole file (and so the whole addon) at load.- **Rebuilt the table defensively** via a new `AddDiseaseTrigger(diseaseId, globalNameAsString)` helper in Disease.lua: each damage-type global is looked up by NAME through `_G` rather than written as a literal key, so a wrong or renamed constant is just a normal `nil` value that gets skipped (and reported once to chat, naming exactly which globals didn’t resolve) instead of crashing the file. This closes off the whole class of bug, not just this one instance.- **Dropped `DAMAGE_TYPE_BLEED` from Fighter’s Bane’s trigger entirely**, rather than swapping in another guess “Bleed” appears to be a status *effect* applied by Physical damage in ESO’s combat model, not a separate `DamageType` of its own, so there may be no such constant to reference at all. Fighter’s Bane is wired to `DAMAGE_TYPE_PHYSICAL` only for now; if a real distinct Bleed damage-type constant is ever confirmed, add it through `AddDiseaseTrigger` the same defensive way, not as a literal key.- Mage’s Bane’s widened trigger is otherwise unchanged in effect Magic, Fire, Cold (was mis-typed Frost), and Shock just spelled correctly now and resolved defensively.### 0.13.1- **Status emotes no longer interrupt a sit/sleep pose already in progress.** New `Rest.IsResting()` exposes Rest.lua’s existing `_isSeated`/`_isSleeping` tracking (already covering `/rnd sit`, `/rnd sleep`, and the hooked native `/sit`-/`/sleep`-family commands, including `/sitchair` so this also covers sitting in a real chair) to `Feedback.CanPlayEmotesNow()`. Hunger/thirst/fatigue/drunkenness/disease status emotes now check this before firing, both on the immediate on-band-entry fire (`CheckBandTransition`, which previously fired unconditionally it’s now gated through the same combat/mounted/major-UI/ resting checks the periodic retrigger already used) and on every periodic retrigger while a category stays bad. `Feedback.CanPlayEmotesNow` is now exposed on the `Feedback` table itself so Disease.lua’s own direct `OnDiseaseChanged` emote call can gate through it too, rather than firing unconditionally.- **Disease redesign, per spec:** – **”Magic Blight” renamed to “Mage’s Bane”** (`magicBlight` → `mageBane` diseaseId). Its overlay art asset is renamed alongside it `Magicpox.dds` → `MagesBane.dds` per request, with the `overlayTexture` path updated to match. Its trigger is widened from `DAMAGE_TYPE_MAGIC` alone to any of the four standard “spell damage” types Magic, Fire, Frost, Shock each now an independent entry in Disease.lua’s new `DAMAGE_TYPE_TO_DISEASES` map. Cure (Restore Magicka: Corn Flower / Lady’s Smock / Vile Coagulant) is unchanged. – **New “Fighter’s Bane”** triggered by martial damage taken (Bleed or Physical), cured with the SAME Restore Health ingredient set Bloodworms already uses (Mountain Flower / Water Hyacinth / Crimson Nirnroot), by request. Now has a generated PLACEHOLDER overlay texture (`FightersBane.dds`, simple colored vignette, not hand-drawn) swap in real custom art whenever you have it, no code changes needed beyond the file itself. – **New “Thief’s Bane”** triggered by martial damage taken (Poison or Disease), cured with the SAME Restore Stamina ingredient set Ashen Lung already uses (Blessed Thistle / Chaurus Egg / Dragon’s Blood the last still unconfirmed, as on Ashen Lung’s own entry). Also given a generated PLACEHOLDER overlay texture (`ThiefsBane.dds`), same caveat as Fighter’s Bane’s above. Note Disease damage now feeds BOTH Bloodworms and Thief’s Bane each rolls independently off its own `diseaseChances` entry on the same qualifying hit. – `Disease.lua`’s old single-disease-per-damage-type `DAMAGE_TYPE_TO_DISEASE` map is replaced with `DAMAGE_TYPE_TO_DISEASES` (a list per damage type), so any number of diseases can independently roll off the same hit. `DAMAGE_TYPE_FIRE`, `DAMAGE_TYPE_FROST`, `DAMAGE_TYPE_SHOCK`, `DAMAGE_TYPE_BLEED`, and `DAMAGE_TYPE_PHYSICAL` are newly referenced here same real-but-individually-unconfirmed-in-a- live-client status the project’s existing `DAMAGE_TYPE_DISEASE`/ `DAMAGE_TYPE_MAGIC` constants already carried; worth a `/script d(damageType)` check the first time each should newly fire. – `RN.DISEASE_ORDER` updated to `{ frostbite, heatstroke, ashenLung, bloodworms, mageBane, fightersBane, thiefsBane }` existing entries kept in their original index positions, new ones appended, per the project’s own stated convention for this list. `/rnd debug disease <1-7>` index range and help text updated to match (the old help text’s 1-5 labels were already stale Bone Chill/Swamp Rot/Ashen Cough/Blood Fever/Wormwood Plague names from before an earlier rename corrected to the current names while touching this anyway). – Settings panel’s `ROLLABLE_DISEASES`/`LOW_CHANCE_DISEASES` lists and description text updated for the rename and two additions. The Healer’s Guide submenu needed no changes it was already built dynamically from `RN.Diseases`/`RN.DISEASE_ORDER`. – **Not migrated**: existing SavedVariables with the old `magicBlight` key under `diseaseChances` are left in place as an inert leftover (same as this project’s earlier disease renames) the new `mageBane`/ `fightersBane`/`thiefsBane` keys are filled in from defaults on next load via the existing recursive-fill, without touching anything you’d already customized under the old key. – **Placeholder texture format note**: `FightersBane.dds`/`ThiefsBane.dds` are uncompressed 32bpp BGRA DDS files (no DX10 header), unlike the project’s existing real-art textures which are all BC7/DX10-compressed 10241024. Both are valid DDS and should load the same way in-game, but the format difference is worth knowing if you swap in real art later matching the existing BC7/DX10 10241024 convention isn’t required, just consistent with what’s already there.### 0.12.5- **Disease notifications now include a cure hint.** New `Feedback.GetCureHintText(diseaseId, severity)` looks up the cheapest ingredient(s) that would actually cure at the given severity (the tier exactly matching it; any rarer tier also works but there’s no reason to suggest it when the matching one is enough) and the curative trait name, e.g. “A dose of Mudcrab Chitin (Protection) would ease this.” Wired into: contraction (“You have contracted Frostbite. A dose of…”); worsening (“Your Heatstroke has worsened to Severe. A dose of Vile Coagulant or Powdered Mother of Pearl (Protection) would ease this.”); and `/checkneeds`’s disease lines. `/rnd debug checkneeds` untouched.- **Added a 1-minut

0

Outfit Switcher (1.2.3)

# Outfit Switcher*by @Kreksar5 and Claude.ai*> **AI-ASSISTED ADDON.** Written with Claude.ai and has not yet been> independently validated in-game for correctness or performance. This> notice will be removed once the addon has seen real play-testing.A tiny ESO addon that lets you swap between your unlocked outfit slots with asingle slash command.## Usage“`/outfit “`- `/outfit 1` switches to outfit slot 1.- If you type a slot number higher than what your account has unlocked, the addon tells you how many slots you actually have and does nothing else.- If you type anything that isn’t a positive whole number (letters, decimals, `0`, negative numbers, empty input, etc.), the addon tells you what’s wrong instead of erroring or silently failing.- Works identically in keyboard and gamepad mode. Feedback is both printed to chat and raised as an on-screen alert, so you’ll see it even if your chat window is closed (common in gamepad play).## Requirements- The Outfit System (Update 17 / “Homestead”, 2017) must be available it is on all live accounts today.- No dependencies, no SavedVariables, no settings menu. Nothing to configure.## How it works| Step | Function used ||—|—|| Check how many outfit slots are unlocked | `GetNumUnlockedOutfits()` || Swap to a given slot | `EquipOutfit(GAMEPLAY_ACTOR_CATEGORY_PLAYER, outfitIndex)` || Confirm what actually happened | `EVENT_OUTFIT_EQUIP_RESPONSE` (`EquipOutfitResult`) || Show feedback in both keyboard and gamepad mode | `ZO_Alert(category, soundId, message)` |`ZO_Alert` automatically routes to the gamepad or keyboard alert-text systemdepending on which UI mode is currently active, so there’s no need forseparate gamepad/keyboard code paths in an addon this small.`EquipOutfit` doesn’t succeed or fail synchronously the game confirms theresult asynchronously via `EVENT_OUTFIT_EQUIP_RESPONSE`. The addon trackswhich slot it just requested and reports the confirmed outcome once thatevent fires: success, already-equipped, invalid slot, locked slot, or outfitswitching being unavailable right now (e.g. certain restricted situations).## Verification notesPer the usual standard for this addon family: every API call below wasconfirmed against the ESOUI wiki, the Update 17 API patch notes, and/or the`esoui/esoui` GitHub source before being used nothing here is guessed.- `GetNumUnlockedOutfits()` confirmed via Update 17 API patch notes.- `EquipOutfit(actorCategory, outfitIndex)` confirmed via ESOUI wiki API page.- `GAMEPLAY_ACTOR_CATEGORY_PLAYER` confirmed via `esoui/esoui` source (`interactwindow_shared.lua`).- `ZO_Alert`, `UI_ALERT_CATEGORY_ERROR`, `UI_ALERT_CATEGORY_ALERT` confirmed via `esoui/esoui` source (`interactwindow_shared.lua`, `tradinghouse_keyboard.lua`).- `SOUNDS.NEGATIVE_CLICK`, `SOUNDS.POSITIVE_CLICK` confirmed via ESOUI wiki Sounds page.- `zo_strtrim` confirmed via `esoui/esoui` source (`localization.lua`).- `EVENT_OUTFIT_EQUIP_RESPONSE` and the `EquipOutfitResult` enum values (`EQUIP_OUTFIT_RESULT_SUCCESS`, `_OUTFIT_ALREADY_EQUIPPED`, `_OUTFIT_INVALID`, `_OUTFIT_LOCKED`, `_OUTFIT_SWITCHING_UNAVAILABLE`) confirmed via ESOUI wiki Events page and `esoui/esoui`’s `ESOUIDocumentation.txt`.## Known limitations- `EVENT_OUTFIT_EQUIP_RESPONSE` doesn’t report which outfit index it’s responding to, so the addon tracks the last-requested slot itself and assumes the response belongs to it. If something else in the game or another addon triggers its own outfit equip in the brief window before the response arrives, the reported slot number in the message could be wrong (the success/failure state itself would still be accurate).## Changelog### 1.2.3- **Standardized the author credit** to `@Kreksar5 and Claude.ai` in the `## Author` manifest field and this README’s byline, and named Claude.ai specifically (rather than generic “AI assistance”) in the manifest description and the AI-assistance disclosure above, matching the crediting convention used across this addon’s companion libraries.### 1.2.2- **Added the required AI-assistance disclosure** to the manifest description and this README, per ESOUI’s addon release rules.### 1.2.1- **Full API audit against the official ESOUI API 101050 documentation.** Every function call, method call, and constant referenced in the addon was cross-checked against the API doc and, where the doc didn’t cover it (manager singletons, `ZO_` helpers), against the live ESOUI source. No invalid or deprecated API usage found `EVENT_OUTFIT_EQUIP_RESPONSE`, `ZO_Alert`, `zo_strtrim`, and `SOUNDS.POSITIVE_CLICK`/`NEGATIVE_CLICK` are all legitimate and correctly used. No code changes required.### 1.2.0- Hooked `EVENT_OUTFIT_EQUIP_RESPONSE` so feedback now reflects the game’s actual confirmed result instead of assuming `EquipOutfit` succeeded. Distinct messages are shown for success, already-equipped, invalid slot, locked slot, and outfit-switching-unavailable.- Merged the changelog into this README.### 1.1.0- Added gamepad support: feedback messages now also raise a `ZO_Alert` on-screen notification (via `UI_ALERT_CATEGORY_ALERT` / `_ERROR` and `SOUNDS.POSITIVE_CLICK` / `NEGATIVE_CLICK`) alongside the existing chat print, so the addon is fully usable when playing in gamepad mode with the chat window closed. No separate gamepad/keyboard code path was needed `ZO_Alert` handles that routing internally.- Hardened `/outfit` argument parsing: – Input is trimmed with `zo_strtrim` before validation. – Only plain, optionally-signed integers are accepted (`^?%d+$`); decimals, hex, exponents, and stray characters are rejected with an explicit message instead of being silently floored or misparsed. – `0` and negative numbers are rejected with a dedicated message (“Slot number must be 1 or higher”) rather than falling through to the generic “not enough slots” message. – Empty input (`/outfit` with no argument) now shows a usage message.- Added README and changelog (changelog later merged into this file in 1.2.0).### 1.0.0- Initial release.- `/outfit ` slash command switches to the given outfit slot via `EquipOutfit(GAMEPLAY_ACTOR_CATEGORY_PLAYER, outfitIndex)`.- Checks unlocked slot count via `GetNumUnlockedOutfits()` and refuses to switch to a slot beyond what’s unlocked.- Basic non-numeric input handling (via `tonumber`).

0

Ultimate BG3 Minsc Build for 2026

Recruited in Act 3, Minsc becomes a powerful Ranger build that can immediately blast enemies on turn one. Our ultimate build guide walks you through how to recruit, progress, and dominate with Minsc in BG3.

0

GoA_HarvestMapUAPatch (1.0)

GoA HarvestMap UA Patch is an unofficial Ukrainian localization and compatibility patch for HarvestMap.This patch provides a complete Ukrainian translation of the HarvestMap interface, settings, menus, and notifications, making the addon fully compatible with the GoA_ESO_UA Ukrainian localization.Features:Full Ukrainian translation of the HarvestMap interfaceUkrainian localization of settings, menus, and notificationsCompatibility with the Ukrainian ESO clientSeamless integration with GoA_ESO_UARegular updates to support new HarvestMap releasesRequirements:HarvestMapGoA_ESO_UAInstallation:Install HarvestMap.Install GoA_ESO_UA.Install GoA HarvestMap UA Patch.Enable all required addons in the ESO Add-Ons menu.Important:This patch does not include the original HarvestMap addon. The original addon must be installed separately through ESOUI or Minion.Credits:Original addon – HarvestMap developersUkrainian localization project – Guards of Amber / GoA_ESO_UACurrent maintenance and updates – IriyaShioThis is an unofficial community project and is not affiliated with or endorsed by the original HarvestMap authors, ZeniMax Online Studios, Bethesda Softworks, or The Elder Scrolls Online.

0

Inspect Vestige by LuckyRome13 (1.0.0)

Inspect Vestigeby LuckyRome13AI disclosure: this addon’s code was written with Claude Code (an AI coding tool). I’m a professional software engineer: I have reviewed and verified the code, tested it in-game — including full two-account peer sync in a real group — and I understand what it does.Have you ever had a groupmate instakill everything and leave you wondering what their build is? Or maybe you’ve been playing with a struggling friend, who wants some tips on how to improve their build. Inspect Vestige allows you to inspect another player’s character loadout in a single window — equipment, skill bars, attributes, core stats, slotted champion points, mundus stone, food/drink, and vampire/werewolf status. Similar in spirit to Destiny 2’s “Inspect Guardian”.Everything is hoverable for its full in-game tooltip, so you can read a build the same way you read your own character sheet.Required libraries — install these firstInspect Vestige will not load without these, and addon managers do not install them for you. If the addon shows a missing-dependency warning on the AddOns screen, this is why.LibGroupBroadcast — v2.0.0 or newer. This is the inspect-another-player feature. v2.x only; the 1.x API is different.LibAddonMenu-2.0 — r38 or newer. The settings panel, and the only way to reach the privacy toggles. LibGroupBroadcast already requires it, so it comes along anyway.Optional:LibCustomMenu — adds the Inspect Vestige entry to your friends / guild / group right-click menus. Without it, the keybind and /iv @Account cover the same ground.Important: what ESO actually allowsESO is not Destiny 2. The game client never receives another player’s gear, skills, or attributes — ZeniMax deliberately withholds this, and there is no API to read it. A true “inspect anyone” addon is impossible in ESO. Please read this section before reporting that you cannot inspect someone.Inspect Vestige works the only way it can: consensually, between players who both run the addon.Yourself — full loadout, always.A group member who also runs Inspect Vestige — full loadout.A group member without the addon — basic public card only.A friend or guildmate not in your group — basic public card only.A stranger in the world — basic public card only.The basic public card is everything ESO does expose about another player: name, class, race, alliance, level, and champion points.Why group-only? The only sanctioned client-to-client data channel in ESO is the group channel (LibGroupBroadcast), and it reaches group members only. There is no equivalent channel for non-grouped friends. If you want to see a friend’s build, group up with them first.It shows up instantly. The group channel is a slow trickle (~32 bytes/second), so a full build takes several seconds to transmit. To avoid making you wait, group members running the addon share their loadout proactively — on joining the group, and whenever they actually change gear, skills, champion points, attributes, or food — so their build is normally already cached before you ever inspect them.Opening an inspectRight-click a name in your friends / guild / group list, then Inspect Vestige (needs LibCustomMenu).The hold-interact wheel when you walk up to a player in the world.A keybind — Settings > Controls > Inspect reticle target./iv to inspect yourself, /iv @Account to inspect someone, /iv settings to open the options.Press Esc or the X to close the window — it will not open the game menu while the window is up.FeaturesEquipment laid out like the character sheet — armor on the left, jewelry and weapons on the right, with the game’s own silhouettes for empty slots. Real item icons and the true in-game item tooltip, including set bonuses and glyphs.Set summary — hover the Equipment header for a per-set breakdown with front/back bar piece counts and an armor-weight tally (how many Light / Medium / Heavy).Per-bar set counts on every gear tooltip, since ESO only counts your active bar’s weapons toward a set.Skill bars with correct morphs, ultimates, and the target’s own skill rank. Werewolves get their transformation bar too.Champion points — every slotted star, colour-coded by discipline (Warfare / Fitness / Craft), with the tooltip scaled to the target’s invested points rather than yours.Core stats — Max Magicka / Stamina / Health, Spell & Weapon Damage, crit chance, crit damage, and penetration, with a Front / Back bar toggle.Mundus, food/drink, and vampire/werewolf status, with live character-scaled tooltip numbers.PrivacyTwo toggles in the settings panel (/iv settings):Share my loadout when asked (default: on) — respond when a group member running the addon inspects you. Turn this off and you neither answer inspect requests nor broadcast proactively; anyone inspecting you sees only your public card.Share with friends only (default: off) — share only with group members on your friends list. Anyone else who inspects you is politely told you share with friends only, rather than being left waiting.An honest note on “friends only”: ESO’s group channel physically delivers every message to the whole group — a message cannot be addressed to one player. So this setting marks the build for your friends and other copies of Inspect Vestige discard it. It is a convention between well-behaved addons, not encryption: someone running a modified addon could still read the data. If that matters to you, turn sharing off entirely. (With no friend in your group, nothing is sent at all.)Known limitationsSkill tooltip numbers are your own. ESO computes ability tooltips from the viewer’s stats and offers no way to render them for another character. Morphs and ranks are always accurate; the magnitudes are relative to you. That is exactly why the Stats row exists — it gives you the target’s real scaling to read those skills against.A player’s back bar is unknown until they weapon-swap at least once. ESO exposes no API for the inactive bar, so it is captured opportunistically on swap. It fills in on its own shortly after they swap.Werewolf detection in human form matches the World skill-line name, which is English-only. Vampire detection and everything else are locale-independent.English only for now.FeedbackBug reports and suggestions are welcome on the comments tab. If something looks wrong on another player’s build, please mention whether they were in your group and whether they also run the addon — that is almost always the deciding detail.

0

GoA_TamrielTradeCentreUAPatch (1)

GoA Tamriel Trade Centre UA Patch is an unofficial Ukrainian localization and compatibility patch for Tamriel Trade Centre (TTC).The patch is designed for players using the GoA_ESO_UA Ukrainian localization and provides Ukrainian language support and compatibility with the Ukrainian ESO client.Features:Ukrainian localization for Tamriel Trade CentreUkrainian translation of the addon interface and settingsCompatibility support for the Ukrainian ESO clientDesigned to work together with GoA_ESO_UARequirements:Tamriel Trade CentreGoA_ESO_UAInstallation:Install Tamriel Trade Centre.Install GoA_ESO_UA.Install this patch.Enable all required addons in the ESO Add-Ons menu.This patch does not include or replace the original Tamriel Trade Centre addon. The original addon must be installed separately.Credits:Original addon Tamriel Trade Centre teamUkrainian localization project Guards of Amber / GoA_ESO_UAThis is an unofficial community project and is not affiliated with or endorsed by the original addon authors, ZeniMax Online Studios, Bethesda Softworks, or The Elder Scrolls Online.

0

Cyberpunk 2077: All 13 Perk Shard Locations (And Phantom Liberty 2.3)

This guide covers all 13 Perk Shard Locations in Cyberpunk 2077 (Patch 2.3). While leveling up your attributes is vital, tracking down Perk Shards gives you the extra points needed to max out multiple branches of your skill trees. There are a total of 13 Perk Shards: 10 in the base game, 3 in the Phantom […]
The post Cyberpunk 2077: All 13 Perk Shard Locations (And Phantom Liberty 2.3) appeared first on AlcastHQ.

0

Vulnerability Tracker (Major + Minor) – Debuff Uptime and Statistics (20260715-0001)

Change Log:——————–20260715-0001- Initial commit: Added files.Description:——————–https://byhumannotai.com/icons/written_by_human_not_ai_light_rect.svgGitHub: https://github.com/du353n7r138/VulnerabilityTrackerOptional Dependencies:LibAddonMenu-2.0 Donations: Please send Columbine, Bugloss, Mountain Flower or Essence of Health Potion (Tri-Pot). I am completely broke. ^_^ Thx! @Duesentrieb Vulnerability Tracker (Major + Minor)Live monitor and statistics for Maj. and Min. Vuln Debuff.Tracker shows remaining duration of Major (Center), Minor (TOP RIGHT) and debuff uptime in % (TOP LEFT).https://i.ibb.co/39kb30Rb/vulngif.gifTimer animation (hapic feedback) when you hit. Its kinda gorgeous.Optional color change from green over yellow to green (remaining time).Show “BOSS” on top when tracking the Boss (or the raid target dummy). Also optional of course.100% coverage of all debuff-sources and IDs. Works on all languages.Tracking Modes: Boss Focus (Smart), Current Target (Dumb).I recommend the smart mode. It works.Optional: Chat Summary outputs uptime % after combat. Uptime – 81.9% – Fight: 2:26minFully customizable. Enjoy!Slash Commands/vulnerabilitytracker → Toggles the UI preview mode so you can easily move things around.If you enjoy Vulnerability Tracker, consider sharing your feedback or supporting its development. I really appreciate it!