Skill: starphaselab/rngneeds-unity (version 0.1.1)

--- name: rngneeds-unity description: Teach agents how to design, implement, explain, and debug gameplay randomness with the RNGNeeds Unity plugin. Use when a request involves RNGNeeds types or concepts such as ProbabilityList, ProbabilityItem, PLCollection, weighted picks, loot tables, gacha, spawn tables, dialogue weighting, AI choice weighting, repeat prevention, depletable lists, card deck extensions, deck order, draw pile, discard pile, hand, graveyard, shuffle plans, influence providers, pick history, seeding, or custom selection methods in Unity/C#. --- # rngneeds-unity Use this skill for RNGNeeds-specific work. If the request is only about generic Unity randomness and does not involve RNGNeeds, handle it normally. ## Work sequence 1. Identify the job: choose a pattern, write code, explain behavior, or debug a setup. 2. Read only the reference files needed for that job. 3. Ground the answer in actual RNGNeeds behavior and API names. 4. Recommend the right mechanic first when the user describes a gameplay goal but not an implementation. 5. If a detail is missing, inspect the package source or docs instead of inventing methods. ## Route by request - **Choose the right RNG pattern**: read `references/decision-guide.md`, then `references/common-patterns.md`, then `references/core-concepts.md` as needed. - **Write or refactor Unity/C# code**: read `references/api-surface.md` and `references/examples.md`. - **Answer tutorial, support, or docs-style questions**: read `references/guide-workflows.md` first, then `references/examples.md`. - **Explain weird probabilities or surprising results**: read `references/pitfalls.md` and `references/core-concepts.md`. - **Build dynamic odds from game state**: read `references/core-concepts.md`, `references/api-surface.md`, and `references/examples.md`. - **Model decks, draw piles, discard piles, hands, graveyards, limited rewards, or finite stock**: read `references/decision-guide.md`, `references/common-patterns.md`, `references/pitfalls.md`, and `references/examples.md`. ## Guardrails - Distinguish **BaseProbability** from the final **Probability** used during selection. - Distinguish **disabled** items from **removed** items, and **depletable** items from infinite ones. - Distinguish **weighted selection** from **deck-order operations**. If the user cares about top, bottom, hand, discard, cut, or shuffle order, prefer deck extensions over `PickValue()`. - Warn that disabled items still occupy probability space, and if selection lands on one that pick is ignored. Disabled or depleted states can reduce result count unless `MaintainPickCountIfDisabled` is enabled. - Warn that repeat prevention changes behavior: `Spread` is fast but more biased, `Repick` is lower bias, `Shuffle` preserves distribution better but does not guarantee zero repeats between separate picks. - Warn that influenced lists recalculate before selection, and final displayed outcomes may normalize. - Warn that `PickValues()` returns a shared internal list reference. Copy it if the caller must keep results after another pick. - Prefer `TryPickValue(...)` when failure matters, especially for value types where `default(T)` can look like a real result. - Note that if an item's value implements `IProbabilityInfluenceProvider`, it overrides an external provider assigned to that item. - Note that deck extensions are order-centric and use simple seeded index/random operations, not the list's weighted selection methods. - Prefer `KeepSeed` or a custom seed provider for deterministic behavior instead of ad hoc randomness hacks. - Reach for custom selection methods only when built-in behavior does not satisfy the requirement. ## Output expectations - Explain *why* a feature fits the gameplay goal, not only *how* to call it. - Keep code examples short and focused on RNGNeeds. - Use RNGNeeds terminology consistently so designers and programmers can discuss the same setup. ## Reference map - `references/core-concepts.md`: terminology and mental model - `references/decision-guide.md`: choose the right feature for the job - `references/common-patterns.md`: common gameplay setups - `references/guide-workflows.md`: tutorial-style workflows distilled from the docs guides - `references/api-surface.md`: high-value classes, properties, and methods - `references/pitfalls.md`: gotchas and debugging heuristics - `references/examples.md`: compact Unity/C# examples - `references/test-prompts.md`: prompt pack for manual skill testing

path: references/api-surface.md
content: # API Surface

This is a practical subset, not an exhaustive dump.

## `ProbabilityList<T>`

### Core configuration

- `ListName`
- `SelectionMethodID`
- `PreventRepeat`
- `ShuffleIterations`
- `PickCountMin`
- `PickCountMax`
- `LinkPickCounts`
- `MaintainPickCountIfDisabled`
- `PickCountCurve`
- `KeepSeed`
- `Seed`
- `CurrentSeed`
- `PickHistory`
- `LastPickCount`
- `LastPickedIndex`
- `LastPickedValue`
- `LastPickedIndices`
- `LastPickedValues`
- `BaseWeight`
- `WeightsPriority`
- `TotalWeight`
- `ItemCount`
- `EnabledItemsCount`
- `UnlockedItemsCount`
- `IsDepletable`
- `IsListInfluenced`

### List editing

- `AddItem(T value, bool enabled = true, bool locked = false)`
- `AddItem(T value, float baseProbability, bool enabled = true, bool locked = false)`
- `AddItem(T value, int weight, bool enabled = true, bool locked = false)`
- `AddItem(ProbabilityItem<T> item)`
- `AddItems(...)`
- `RemoveItem(...)`
- `RemoveItemAtIndex(...)`
- `ClearList()`
- `GetProbabilityItem(int index)`
- `TryGetProbabilityItem(int index, out ProbabilityItem<T> item)`
- `TryGetProbabilityItem(T value, out ProbabilityItem<T> item)`
- `IndexOf(...)`

### Probability and weights

- `GetItemProbability(int index)`
- `GetItemBaseProbability(int index)`
- `SetItemBaseProbability(int index, float baseProbability, bool normalize = true)`
- `AdjustItemBaseProbability(int index, float amount)`
- `NormalizeProbabilities()`
- `ResetAllProbabilities()`
- `GetItemWeight(int index)`
- `SetItemWeight(int index, int weight)`
- `CalculatePercentageFromWeights()`
- `ResetWeights()`
- `RecalibrateWeights()`

### Item state and influence helpers

- `SetItemEnabled(int index, bool enabled)`
- `SetAllItemsEnabled(bool enabled)`
- `SetItemLocked(int index, bool locked)`
- `SetAllItemsLocked(bool locked)`
- `SetItemProperties(int index, float baseProbability, bool enabled, bool locked)`
- `SetItemInfluenceProvider(int index, IProbabilityInfluenceProvider influenceProvider)`
- `SetItemInfluenceSpread(int index, Vector2 spread)`
- `SetItemInvertInfluence(int index, bool invertInfluence)`

### Selection

- `PickValue()`
- `TryPickValue(out T value)`
- `TryPickValueWithIndex(out T value, out int index)`
- `PickValues()`
- `PickValues(int pickCount)`
- `PickValues(int pickCountMin, int pickCountMax)`
- `PickValues(List<T> listToFill)`
- `PickValues(List<T> listToFill, int pickCount)`
- `PickValues(List<T> listToFill, int pickCountMin, int pickCountMax)`

### History and diagnostics

- `GetLastPickedIndices(List<int> listToFill)`
- `GetLastPickedValues(List<T> listToFill)`
- `SetHistoryCapacity(int capacity)`
- `ClearHistory()`
- `RunTest()`

### Depletable list helpers

- `RefillItems()`
- `SetAllItemsUnits(int units)`
- `SetAllItemsMaxUnits(int units)`
- `SetAllItemsDepletable(bool depletable)`
- `SetItemDepletable(int index, bool depletable = true, int units = 1, int maxUnits = 1)`
- `SetAllItemsDepletableProperties(bool depletable = true, int units = 1, int maxUnits = 1)`
- `GetTotalUnits()`
- `GetTotalMaxUnits()`

## `ProbabilityItem<T>`

### Core properties

- `Value`
- `BaseProbability`
- `Probability`
- `Enabled`
- `Locked`
- `Weight`

### Influence

- `InfluenceSpread`
- `InvertInfluence`
- `InfluenceProvider`
- `ValueIsInfluenceProvider`
- `IsInfluencedItem`
- `GetInfluencedProbability(float influence)`

### Depletable item state

- `IsDepletable`
- `Units`
- `MaxUnits`
- `IsDepleted`
- `IsSelectable`
- `Refill()`
- `SetDepletable(bool depletable = true, int units = 1, int maxUnits = 1)`

## Card Deck Extensions on `ProbabilityList<T>`

Use these when the list should behave like an ordered deck, not a weighted table.

### Peek and draw

- `PeekTopItem()`
- `TryPeekTopItem(out ProbabilityItem<T> item)`
- `PeekTop()`
- `TryPeekTop(out T value)`
- `PeekAtItem(int index)`
- `TryPeekAtItem(int index, out ProbabilityItem<T> item)`
- `DrawTopItem()`
- `TryDrawTopItem(out ProbabilityItem<T> item)`
- `DrawAtItem(int index)`
- `TryDrawAtItem(int index, out ProbabilityItem<T> item)`

### Place and move

- `PlaceItemOnTop(ProbabilityItem<T> item)`
- `TryPlaceItemOnTop(ProbabilityItem<T> item)`
- `PlaceItemOnBottom(ProbabilityItem<T> item)`
- `TryPlaceItemOnBottom(ProbabilityItem<T> item)`
- `PlaceAtItem(int index, ProbabilityItem<T> item)`
- `TryPlaceAtItem(int index, ProbabilityItem<T> item)`
- `DealItemToDeck(ProbabilityList<T> target)`
- `TryDealItemToDeck(ProbabilityList<T> target, out ProbabilityItem<T> item)`

### Reorder and shuffle

- `TryCut(int index)`
- `TryReverseDeck()`
- `CreateShufflePlan()`
- `CreateShufflePlan(IDeckShuffleMethod shuffleMethod)`
- `ApplyShufflePlan(DeckShufflePlan shufflePlan)`
- `TryApplyShufflePlan(DeckShufflePlan shufflePlan)`
- `ShuffleDeck()`
- `TryShuffleDeck()`
- `ShuffleDeck(IDeckShuffleMethod shuffleMethod)`
- `TryShuffleDeck(IDeckShuffleMethod shuffleMethod)`
- `RiffleShuffle()`
- `TryRiffleShuffle()`
- `OverhandShuffle()`
- `TryOverhandShuffle()`
- `CutNearHalf()`
- `TryCutNearHalf()`

### Deck shuffle planning types

- `IDeckShuffleMethod`
- `DeckShufflePlan`
  - `MethodId`
  - `DisplayName`
  - `Steps`
  - `FinalOrder`
- `DeckShuffleStep`
  - `StepType`
  - `Description`
  - `SourceIndices`
  - `ResultIndices`
- `DeckShuffleMethods`
  - `Default`
  - `Uniform`
  - `Riffle`
  - `Overhand`
  - `CutNearHalf`

## `PLCollection<T>`

Use this when many named lists belong together.

- `AddList(...)`
- `RemoveList(...)`
- `GetList(...)`
- `SetListName(...)`
- `ClearCollection()`
- `ClearList(...)`
- `ClearAllLists()`
- `MoveListUp(int index)`
- `MoveListDown(int index)`
- `PickValueFrom(...)`
- `PickValuesFrom(...)`
- `PickValuesFromAll()`
- `RefillList(...)`
- `RefillAllLists()`

## `IProbabilityInfluenceProvider`

Implement:

- `float ProbabilityInfluence`
- `string InfluenceInfo`

Return a meaningful `-1..1` influence value and a designer-readable explanation.

## `ISelectionMethod`

Implement when built-in selection behavior is not enough.

- `string Identifier`
- `string Name`
- `NativeList<int> SelectItems(IProbabilityList probabilityList, int pickCount)`

Register it with `RNGNeedsCore.RegisterSelectionMethod(...)`.

## `RNGNeedsCore`

Useful static entry points:

- `DefaultSelectionMethodID`
- `RegisteredSelectionMethods`
- `NewSeed`
- `SetSeedProvider(ISeedProvider seedProvider)`
- `ResetSeedProvider()`
- `RegisterSelectionMethod(ISelectionMethod selectionMethod)`
- `GetSelectionMethod(string identifier)`
- `WarmupHistoryEntries(int count)`


path: references/common-patterns.md
content: # Common Patterns

## Weighted loot drop

Use one `ProbabilityList<Item>`.

- one pick for a single drop
- multiple picks for bundles
- use weights if designers think in rarity tiers

Add repeat prevention only if back-to-back duplicates feel bad.

## Chest with categories

Use one higher-level table to choose category, then one table per category.

Good fits:

- `ProbabilityList<ItemCollection>` where each collection owns its own `ProbabilityList<Item>`
- `PLCollection<T>` when many named tables must be organized together

This keeps authoring modular and makes balancing easier.

## Gacha or summon banner

Use a `ProbabilityList<Character>` or `ProbabilityList<Reward>`.

Common additions:

- fixed multi-pulls with `PickValues(10)`
- seeded pulls for reproducible tests
- pick history if later systems need to inspect outcomes

If the design requires pity or guarantee logic, treat RNGNeeds as one part of the system and add explicit game logic around it.

## Dynamic spawn selection

Use `ProbabilityList<SpawnLocation>` or `ProbabilityList<EnemyType>` plus influence providers.

Example signals:

- distance to player
- current threat level
- time of day
- room occupancy

Use `InvertInfluence` when one signal should boost one option while suppressing another.

## AI decision weighting

Use `ProbabilityList<Action>` or `ProbabilityList<DamageType>`.

Good when the AI should feel varied but still biased toward context.

Pair with influence providers for health, cooldown state, stamina, or player distance.

## Dialogue, voice lines, and audio responses

Use `ProbabilityList<AudioClip>` or `ProbabilityList<string>`.

Add repeat prevention so the same bark does not fire twice in a row. Usually `Repick` is a good default.

## Unique rewards

Use a depletable list where each item has `Units = 1`.

This is the cleanest way to say “once claimed, it is gone until refill.”

## Finite pool with duplicates but no positional order

Use a depletable list where each unique item is one entry and `Units` holds the copy count.

This fits “draw without replacement” systems where exhaustion matters but top/bottom position does not.

That includes lightweight card-deck style workflows where the user wants multiple copies of the same card but does **not** care about live ordering, shuffling behavior, peeking, or moving cards between gameplay zones.

## True ordered card deck

Use Card Deck Extensions on `ProbabilityList<Card>` when the design cares about top-of-deck order.

Good fits:

- drawing from the top into a hand
- discarding to the bottom of another pile
- maintaining separate draw, hand, table, discard, or graveyard zones
- cutting, reversing, or otherwise reordering a live deck

Prefer deck helpers like `TryDrawTopItem(...)`, `TryPlaceItemOnTop(...)`, and `TryPlaceItemOnBottom(...)` over manual index code when the built-in flow already matches the gameplay.

## Inspectable physical-style shuffle

Use shuffle plans when the deck should behave like a physical stack and the shuffle itself should be explainable.

Good fits:

- card battlers or tabletop-inspired systems
- debug tools that need to show how the order changed
- tutorials that compare `Riffle`, `Overhand`, and `CutNearHalf`

Typical flow:

1. create a `DeckShufflePlan`
2. inspect or print its steps
3. apply it to the deck

## Multi-zone card flow

Use one `ProbabilityList<Card>` per gameplay zone.

Common zones:

- draw pile
- hand
- discard pile
- table / board
- graveyard / exile

Move `ProbabilityItem<T>` references between zones when card identity and current state should stay attached to the moved card.

## Distinct multi-pick rewards

Use depletable lists plus `PickValues(count)`.

This gives distinct results naturally while units remain.

If the requested count exceeds total remaining units, expect fewer results unless infinite items are mixed in.

## Weighted bool or gate checks

Use `ProbabilityList<bool>` for simple yes/no random gates.

Useful for:

- should spawn
- should crit
- should play idle animation

Keep it only for simple switches. If the design is richer than yes/no, model explicit outcomes instead.


path: references/core-concepts.md
content: # Core Concepts

## Mental model

RNGNeeds centers on `ProbabilityList<T>`, a list of `ProbabilityItem<T>` entries. Each item has a value plus selection metadata.

Treat it as a gameplay-facing random system, not just a helper for `Random.Range`.

## Key terms

- **Probability List**: the container of possible outcomes.
- **Probability Item**: one outcome plus configuration.
- **BaseProbability**: the designed probability before runtime adjustment.
- **Probability**: the effective probability after influence and normalization.
- **Selection Method**: the algorithm used to select values.
- **Pick Count**: how many values are selected in one operation.
- **Repeat Prevention**: logic that reduces or removes consecutive repeats.
- **Influence Provider**: an object implementing `IProbabilityInfluenceProvider` that pushes odds up or down.
- **Depletable List**: a list where item units can be consumed.
- **Deck Extensions**: order-centric helpers that treat a `ProbabilityList<T>` like a card deck, with top at index `0` and bottom at the last index.
- **Pick History**: recent picks stored by index and reused by helper APIs.

## Base probability vs resulting probability

Do not equate the number shown in `BaseProbability` with what the player actually experiences.

- Runtime influence can push an item up or down.
- If totals exceed 100%, RNGNeeds normalizes the list before selecting.
- Disabled or depleted items can change perceived outcomes and pick counts.
- Repeat prevention can intentionally distort back-to-back behavior.

## Disabled items

Disabled items still exist in the probability space. A selection can land on them, then yield no usable result.

This means:

- returned pick count can be lower than requested
- single-value picks can fail
- `MaintainPickCountIfDisabled` trades exact distribution for “keep filling until count is reached” behavior

## Depletable lists

Use depletable lists for finite stock.

- The list must have `IsDepletable = true`.
- Individual items also have depletable state plus `Units` and `MaxUnits`.
- Consuming units makes depleted items behave like unavailable entries.

Use this for unique rewards, limited spawns, finite stock, or deck-like pools where exhaustion and duplicate-copy counts matter but live top/bottom order does not.

This means a simple card pool can still be modeled as a depletable list when the user does not care about shuffling, peeking, cutting, draw-pile vs discard-pile flow, or any other order-centric behavior.

## Deck extensions

Use deck extensions when **order itself** is part of the gameplay.

Typical signals:

- draw from the top
- place on the bottom
- move cards between draw pile, hand, discard, or table zones
- cut or shuffle a deck as an ordered stack
- inspect or explain how a shuffle changed the deck

Important consequences:

- top of deck is index `0`
- these operations are **not** weighted picks
- shuffle helpers use seeded index-based randomness to reorder items
- moving or reordering cards changes positional gameplay, not just probabilities

Use ordinary `PickValue()` or `PickValues()` when the user wants weighted outcome selection. Use deck extensions when the user wants card-flow or positional behavior.

## Repeat prevention

Use repeat prevention when the pool is still conceptually infinite but consecutive duplicates feel bad.

- `Spread`: fastest, strongest bias
- `Repick`: moderate speed, lower bias
- `Shuffle`: preserves distribution best, reduces repeats after selection, weaker across separate picks

Do not use repeat prevention as a substitute for finite inventory.

## Influence

Influence is a `float` from `-1` to `1` supplied by `IProbabilityInfluenceProvider`.

Each influenced item maps that input through its **Influence Spread**.

Important consequences:

- if one item is influenced, the list is treated as influenced
- probabilities are recalculated before picks
- positive influence on one item can lower others after normalization
- `InvertInfluence` lets the same provider push different items in opposite directions

## Seeding and determinism

Each pick uses a seed.

- default behavior: generate a new seed each selection
- `KeepSeed = true`: reuse the same seed
- `Seed = 1337`: set a deterministic seed when `KeepSeed` is on
- custom global behavior: implement `ISeedProvider` and call `RNGNeedsCore.SetSeedProvider(...)`

Use this for replays, debugging, and reproducible tests.

## Pick history

History stores indices, then helper properties expose values.

This matters because:

- `LastPickedValue` and `LastPickedValues` come from history
- history-aware behavior affects repeat prevention
- removing items clears history safety assumptions because indices change

## Shared result lists

`PickValues()` returns a shared internal list reference.

If you need to preserve results, copy them into your own list.

## Weights

RNGNeeds also supports weights.

Use weights when designers think in relative rarity rather than exact percentages. Keep in mind that weights are a friendlier authoring surface, not magically different randomness.


path: references/decision-guide.md
content: # Decision Guide

Start from the gameplay requirement, then map it to RNGNeeds.

## If the user wants one weighted random result

Use `ProbabilityList<T>` with `PickValue()`.

Examples: one loot drop, one enemy archetype, one dialogue bark.

## If the user wants multiple weighted results at once

Use `ProbabilityList<T>` with `PickValues(...)` and configure pick counts.

- fixed amount: `PickValues(count)`
- variable amount: `LinkPickCounts = false`, set `PickCountMin`, `PickCountMax`, optionally `PickCountCurve`

## If the user wants limited stock or true exhaustion without positional deck order

Use a **depletable list**.

Choose this for:

- unique rewards
- finite loot pool
- limited enemy reinforcements
- card pools where duplicate copies matter but live deck order does not
- any finite pool where order is not itself gameplay

Do **not** use repeat prevention for this.

## If the user wants a true ordered deck with top or bottom behavior

Use **Card Deck Extensions** on `ProbabilityList<T>`.

Choose this for:

- draw from top of deck
- place cards on top or bottom
- move cards between draw pile, hand, discard pile, graveyard, or table zones
- cut or reorder a deck while preserving card order

Reach for methods like `TryDrawTopItem(...)`, `TryPlaceItemOnTop(...)`, `TryPlaceItemOnBottom(...)`, `TryCut(...)`, and `DealItemToDeck(...)`.

## If the user wants an explainable or inspectable shuffle

Use **shuffle plans**.

Choose this for:

- physical-card-feel shuffles
- debugging or visualizing deck order changes
- tutorials that should explain what the shuffle did
- deterministic “plan first, apply second” workflows

Reach for `CreateShufflePlan(...)`, `ApplyShufflePlan(...)`, or `ShuffleDeck(..., DeckShuffleMethods.Riffle/Overhand/CutNearHalf)`.

## If the user wants “do not repeat twice in a row” but not finite stock

Use **repeat prevention**.

- best feel-first choice: `Repick`
- best distribution preservation: `Shuffle`
- fastest but more biased: `Spread`

## If the user wants probabilities to react to game state

Use **influence providers**.

Choose this for:

- health-based drops
- distance-based spawns
- reputation-based dialogue
- time-of-day enemy tables

Use `IProbabilityInfluenceProvider`, `InfluenceSpread`, and possibly `InvertInfluence`.

## If the user wants deterministic or replayable results

Use seeding.

- same list, same results: `KeepSeed = true`
- known sequence: assign `Seed`
- global custom rule: `RNGNeedsCore.SetSeedProvider(...)`

## If the user wants designer-friendly rarity knobs instead of raw percentages

Use weights.

Look at `Weight`, `BaseWeight`, `WeightsPriority`, and related weight conversion helpers.

## If the user wants grouped tables or multi-stage loot

Use nested lists or `PLCollection<T>`.

Choose this for:

- chest chooses category, then item
- biome chooses subtable, then encounter
- deck builder chooses a collection, then cards from it

## If the user wants exact top-of-deck or bottom-of-deck behavior

Do **not** use weighted random picks.

Prefer deck extensions first.

Use manual index traversal only when the user needs a lower-level custom flow that the built-in deck helpers do not already express.

## If the user is debugging “wrong probabilities”

Check these first:

1. influenced list normalization
2. disabled or depleted items
3. repeat prevention bias
4. `MaintainPickCountIfDisabled`
5. shared `PickValues()` result reuse


path: references/examples.md
content: # Examples

## Simple weighted loot roll

```csharp
using RNGNeeds;
using UnityEngine;

public class LootRoller : MonoBehaviour
{
    public ProbabilityList<Item> loot;

    public Item RollOne() => loot.PickValue();
}
```

## Distinct rewards from a finite pool

```csharp
using System.Collections.Generic;
using RNGNeeds;
using UnityEngine;

public class RewardChest : MonoBehaviour
{
    public ProbabilityList<Item> rewards;

    private void Awake()
    {
        rewards.IsDepletable = true;
        rewards.SetAllItemsDepletableProperties(true, 1, 1);
        rewards.MaintainPickCountIfDisabled = true;
    }

    public List<Item> OpenChest(int count)
    {
        rewards.RefillItems();
        return new List<Item>(rewards.PickValues(count));
    }
}
```

This matches the docs-preferred distinct-reward flow more closely than the older pick-then-disable loop.

## Health-based dynamic drop chance

```csharp
using RNGNeeds;
using UnityEngine;

public class HealthManager : MonoBehaviour, IProbabilityInfluenceProvider
{
    public float maxHealth = 100f;
    public float currentHealth = 100f;

    public float HealthPct => currentHealth / maxHealth;
    public float ProbabilityInfluence => Mathf.Lerp(1f, -1f, HealthPct);
    public string InfluenceInfo => $"Health {HealthPct:P0} -> influence {ProbabilityInfluence:F2}";
}
```

Use this with an influenced item whose spread increases the drop chance when the player is hurt.

```csharp
using RNGNeeds;
using UnityEngine;

public class LootDrops : MonoBehaviour
{
    public HealthManager health;
    public ProbabilityList<Item> loot;

    private void Awake()
    {
        loot.SetItemInfluenceProvider(0, health);
        loot.SetItemInfluenceSpread(0, new Vector2(-5f, 20f));
    }
}
```

## Prevent repeated voice lines

```csharp
using RNGNeeds;
using UnityEngine;

public class UnitAudio : MonoBehaviour
{
    public ProbabilityList<AudioClip> selectResponses;

    private void Awake()
    {
        selectResponses.PreventRepeat = PreventRepeatMethod.Repick;
    }

    public AudioClip GetResponse() => selectResponses.PickValue();
}
```

## Deterministic test setup

```csharp
using RNGNeeds;

public static class LootTestSetup
{
    public static void ForceDeterministicRuns(ProbabilityList<Item> list)
    {
        list.KeepSeed = true;
        list.Seed = 1337;
    }
}
```

## Multi-stage chest table

```csharp
using System.Collections.Generic;
using RNGNeeds;
using UnityEngine;

public class ItemCollection : ScriptableObject
{
    public ProbabilityList<Item> items;

    public List<Item> PickItems() => new List<Item>(items.PickValues());
}

public class SimpleChest : MonoBehaviour
{
    public ProbabilityList<ItemCollection> weaponCollections;
    public ProbabilityList<Item> armor;

    public List<Item> Open()
    {
        var picked = new List<Item>();

        foreach (var collection in weaponCollections.PickValues())
            picked.AddRange(collection.PickItems());

        picked.AddRange(armor.PickValues());
        return picked;
    }
}
```

## Top-of-deck draw with finite cards

Use deck extensions first when order matters.

```csharp
using RNGNeeds;

public static class DeckDraw
{
    public static ProbabilityItem<Card> DrawOne(ProbabilityList<Card> drawPile)
    {
        drawPile.TryDrawTopItem(out var drawnItem);
        return drawnItem;
    }
}
```

Use manual index traversal only when you need a custom low-level flow that the built-in deck helpers do not cover.

## Move cards between zones

```csharp
using RNGNeeds;

public static class CardFlow
{
    public static bool DrawToHand(ProbabilityList<Card> drawPile, ProbabilityList<Card> hand)
    {
        if (!drawPile.TryDrawTopItem(out var drawnItem))
            return false;

        return hand.TryPlaceItemOnBottom(drawnItem);
    }
}
```

## Create and apply a shuffle plan

```csharp
using RNGNeeds;
using UnityEngine;

public class DeckShufflePreview : MonoBehaviour
{
    public ProbabilityList<Card> drawPile;

    public void ApplyRifflePlan()
    {
        var plan = drawPile.CreateShufflePlan(DeckShuffleMethods.Riffle);
        Debug.Log($"{plan.DisplayName}: {plan.Steps.Count} steps");
        drawPile.ApplyShufflePlan(plan);
    }
}
```

## Deal directly from one deck to another

```csharp
using RNGNeeds;

public static class DeckTransfers
{
    public static bool MoveTopCard(ProbabilityList<Card> source, ProbabilityList<Card> target)
    {
        return source.TryDealItemToDeck(target, out _);
    }
}
```


path: references/guide-workflows.md
content: # Guide Workflows

These workflows are distilled from the docs guides so the skill can answer in the same shape as RNGNeeds documentation, not only as raw API help.

## Selecting distinct values

Recommend this order:

1. Use **Depletable Lists** as the primary solution.
2. Set the list as depletable.
3. Keep each unique reward at `1 / 1` units unless duplicates are desired.
4. Turn on `MaintainPickCountIfDisabled` when the caller expects an exact number of unique results.
5. Refill before each independent reward session if the pool should reset between sessions.

Docs-backed nuance:

- disabled items still remain in the probability space
- if selection lands on a disabled item, that pick is ignored
- this can reduce the final pick count unless `MaintainPickCountIfDisabled` keeps trying

Reference pattern:

```csharp
public List<Reward> PickRewards(int count)
{
    rewards.RefillItems();
    rewards.MaintainPickCountIfDisabled = true;
    return rewards.PickValues(count);
}
```

Only mention the older “pick then disable” loop as a fallback or historical approach.

## Probability influence quick setup

For tutorial-style help, teach this sequence:

1. Start with a simple `ProbabilityList<bool>` or another tiny example.
2. Explain that influence UI is hidden behind advanced drawer options.
3. Introduce `IProbabilityInfluenceProvider` with both `ProbabilityInfluence` and `InfluenceInfo`.
4. Explain **Spread** as the designer-facing control for how much the provider can move the final chance.
5. Show one `PickValue()` call at the end so the system feels concrete.

Default examples that fit well:

- hacking success chance
- critical strike chance
- monster spawn chance

## Probability influence in code

When the user asks for a code-first setup:

1. Put the list and the gameplay stats on the same component when that makes sense.
2. Have the component implement `IProbabilityInfluenceProvider`.
3. Build the list in `Start()` or another initialization step.
4. Assign the provider to both the positive and negative outcomes if the design wants mirrored behavior.
5. Use `InvertInfluence` on the counter-outcome when one signal should raise one result while lowering the other.

Docs-backed helper methods that are valid to use:

- `SetItemInfluenceProvider(index, provider)`
- `SetItemInfluenceSpread(index, spread)`
- `SetItemInvertInfluence(index, true)`

Direct `ProbabilityItem<T>` property assignment is also fine when the code already holds item references.

This is the clearest docs-backed pattern for crit chance, skill checks, and binary success/failure systems.

## PLCollection workflow

For grouped content, teach `PLCollection<T>` as a named container for multiple lists.

Good docs-shaped advice:

1. create a collection
2. name the lists clearly
3. retrieve or pick by name when the categories are content-facing
4. use index-based access only when the system is tightly controlled internally

Good example categories:

- Friendly / Neutral / Hostile responses
- biome encounter groups
- loot families

## Depletable list examples

Use the docs examples when the user is really asking about gameplay design, not only API syntax.

Strong examples to reach for:

- resource deposit with common infinite resources plus limited rares
- deposit depletion triggered by mining attempts
- deposit depletion triggered by one tracked resource running out
- card/deck style limited draws

This is useful when the answer should explain design tradeoffs, not only method names.

## Card deck extensions workflow

When the user is really describing a card-flow system, teach this sequence:

1. Author a starting deck recipe with a `ProbabilityList<Card>`.
2. Build one live `ProbabilityList<Card>` per zone such as draw pile, hand, discard, or table.
3. Use deck helpers for card movement and reordering.
4. Shuffle or cut the live deck when order should change.
5. Use weighted picks only if another part of the design is actually probability-table driven.

Good docs-shaped advice:

- top of deck is index `0`
- moving a `ProbabilityItem<T>` between zones preserves card-level state better than recreating raw values
- `TryDrawTopItem(...)` plus `TryPlaceItemOnBottom(...)` is the core draw/discard pattern
- `DealItemToDeck(...)` is a strong fit when one zone should transfer its top card directly to another

## Inspectable shuffle-plan workflow

When the user wants the shuffle itself to be visible or explainable, teach this sequence:

1. choose a shuffle method such as `DeckShuffleMethods.Riffle`, `Overhand`, or `CutNearHalf`
2. call `CreateShufflePlan(...)`
3. inspect or log the plan steps
4. apply the plan with `ApplyShufflePlan(...)`

Use this framing for tutorial content, debug tools, and “make the shuffle feel physical” requests.

## Tone and framing

When responding in a docs-like mode:

- start with the gameplay goal
- recommend the feature before dumping code
- explain what the designer configures in inspector versus what the coder adds in code
- call out advanced-drawer requirements only when they matter to the setup


path: references/pitfalls.md
content: # Pitfalls

## `PickValues()` returns a shared list

Do not hold onto the returned list across later picks unless you copy it.

Bad assumption: “I stored the last result, so it is stable forever.”

Safe pattern:

```csharp
var stableCopy = new List<Item>(lootTable.PickValues(3));
```

## Disabled items can silently lower pick counts

Disabled items still occupy probability space.
If selection lands on one, that pick is ignored.

Symptoms:

- requested 100 picks, got about 66
- `PickValue()` returned `null` or `default(T)`

Check `MaintainPickCountIfDisabled` if the design values exact count more than exact distribution.

## Failed single picks can look real for value types

If a failed single pick returns `0`, `false`, or another default value, do not assume it was a valid selection.

Prefer `TryPickValue(out var value)` when success matters.

## Repeat prevention changes feel and distribution

Do not promise “same probabilities, just no repeats” unless you are specifically using `Shuffle` and even then explain the limitation.

- `Spread`: stronger correction, more bias
- `Repick`: lower bias, still altered
- `Shuffle`: better preservation, weaker cross-pick guarantees

## Influence can make preview math look surprising

If one item goes up, other items can effectively go down after normalization.

Common mistaken conclusion: “RNGNeeds ignored my spread.”

Often the real cause is that total effective probability exceeded 100%, so normalization changed the final percentages.

## Value-as-provider overrides external provider

If an item's value implements `IProbabilityInfluenceProvider`, that provider takes precedence over an externally assigned provider.

Debug this first when the wrong influence source seems to be active.

## Depletable items do nothing unless the list is depletable

Setting `item.IsDepletable = true` is not enough by itself.

The parent list also needs `list.IsDepletable = true`.

## Maintain-pick-count can intentionally bend outcomes

`MaintainPickCountIfDisabled` keeps filling until it reaches the requested count.

That is useful, but it no longer represents the same distribution as “pick once and ignore disabled/depleted results.”

## Weighted picks and deck operations solve different problems

Do not answer a top-of-deck or hand/discard workflow with `PickValue()` just because cards are involved.

Use weighted picks for outcome selection.
Use deck extensions for ordered card flow.

If the user says “draw from top”, “put on bottom”, “shuffle deck”, or “move from draw pile to hand”, treat that as a deck-order problem first.

## Shuffle helpers do not use weighted selection

Deck shuffle helpers reorder by seeded index/random operations.

They do **not** consult item probabilities the way `PickValue()` does.

Common mistaken assumption: “My higher-probability card should stay more likely to appear near the top after a shuffle.”

That is not what these helpers are for. They are deck-order tools, not weighted pick tools.

## Manual index traversal is now a fallback, not the default deck answer

Manual traversal still works for custom behavior.

But when the built-in deck helpers already match the gameplay, prefer them over custom loops. They communicate intent better and usually preserve moved `ProbabilityItem<T>` references correctly.

## Deck reordering changes positional gameplay and clears history-sensitive assumptions

Cutting, reversing, applying shuffle plans, and moving cards between zones changes item order directly.

That means any reasoning tied to previous positions or pick history should be re-checked after a reorder.

## Very small enabled probability can cause skipped selection

RNGNeeds has fail-safe protection when maintaining pick count would otherwise take too long or hang because enabled probability is tiny.

If nothing is returned and a warning appears, check:

- too few enabled items
- too many disabled/depleted items
- too large pick count
- influenced outcomes driving enabled probability near zero

## History is index-based

History refers to item indices, not immutable IDs.

Removing items can invalidate assumptions about old picks, so do not build persistence logic on raw indices without your own mapping.

## Weights are authoring helpers, not sacred percentages

When weights are converted back to probabilities, rounding and snapping can make the displayed percentages differ slightly from an intended exact decimal setup.

Use precise probabilities when exact percentages matter more than friendly weight editing.


path: references/test-prompts.md
content: # Test Prompts

Use these to manually probe whether the skill routes well and answers in an RNGNeeds-native way.

## What to look for

A strong answer should usually:

- choose the right RNGNeeds feature before dumping code
- use real RNGNeeds API names
- explain RNGNeeds-specific gotchas instead of generic randomness advice
- avoid inventing methods or hiding tradeoffs

## Pattern selection

1. I need a Unity loot table with three unique rewards per chest. Should I use repeat prevention or depletable lists in RNGNeeds?
2. What RNGNeeds setup fits an NPC response system with Friendly, Neutral, and Hostile dialogue pools?
3. I want a card deck with duplicate cards and true exhaustion. What RNGNeeds pattern should I use?
4. In RNGNeeds, when should I use Card Deck Extensions instead of a plain depletable-list setup?
5. How should I model draw pile, hand, and discard pile with RNGNeeds?

## Tutorial and support

6. Show me a beginner-friendly RNGNeeds setup for dynamic hacking success using Probability Influence.
7. Explain RNGNeeds depletable lists like I’m handing the setup to a designer.
8. How do I organize multiple spawn tables with PLCollection?
9. Show me how to explain an inspectable riffle shuffle plan in RNGNeeds.

## Code generation

10. Write a Unity component that uses `ProbabilityList<bool>` for crit chance and adjusts it from weapon durability.
11. Show a `PickRewards(int count)` method that returns distinct rewards from a `ProbabilityList<Reward>`.
12. Give me a minimal `IProbabilityInfluenceProvider` example for health-based loot drops.
13. Show a minimal RNGNeeds example that draws a card from the top of one deck and places it on the bottom of another.
14. Give me a short Unity example that creates a `DeckShufflePlan` and applies it.

## Debugging

15. My RNGNeeds list asks for 5 picks but sometimes returns only 3. What should I check?
16. Why does `PickValue()` sometimes return `0` from my `ProbabilityList<int>`?
17. I turned on repeat prevention and now my rare item feels less common. Is that expected?
18. My influence provider is assigned but the wrong influence seems to apply. What could override it?
19. In RNGNeeds, if one item in my `ProbabilityList` is disabled, does it still affect picks and probabilities?
20. I asked for top-of-deck draw behavior, but the answer used `PickValue()`. Why is that the wrong mental model?

## Determinism and testing

21. How do I make RNGNeeds produce repeatable results for tests and replays?
22. What is the difference between `BaseProbability` and the actual probability used during selection?
23. Are RNGNeeds shuffle plans deterministic relative to the list seed?

## Quick scoring rubric

- **Pass**: right mechanic, real API, no important misinformation
- **Partial**: mostly right, but vague, incomplete, or slightly misleading
- **Fail**: wrong mechanic, invented API, or misleading explanation of RNGNeeds behavior


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)