Skip to content

RecipeManifest

Namespace Nfty.Core.Model in assembly Nfty.Ticket.

public record RecipeManifest : ISchemaVersioned

A complete template for one character type: which layers, in what order, and which combinations are illegal.

Constructors

RecipeManifest(string, string, IReadOnlyList<string>, IReadOnlyList<IncompatibilityRule>, int, IReadOnlyDictionary<string, double>?, bool)

public RecipeManifest(string Id, string Name, IReadOnlyList<string> LayerOrder, IReadOnlyList<IncompatibilityRule> Rules, int SchemaVersion = 2, IReadOnlyDictionary<string, double>? AbsentPercent = null, bool PartialAlpha = false);

Parameters

  • Id (string) - Stable identifier, unique within its CookBook.
  • Name (string) - Display name.
  • LayerOrder (IReadOnlyList<string>) - Ingredient ids bottom-to-top. This — not the ingredient collection's own order — is what generation rolls and composites, so an ingredient missing from it is never drawn.
  • Rules (IReadOnlyList<IncompatibilityRule>) - Incompatibility rules applied to a rolled selection; a violation costs a re-roll.
  • SchemaVersion (int) - The manifest format version; see Schema.
  • AbsentPercent (IReadOnlyDictionary<string, double>?) - How often each layer is left out entirely, as a PERCENT, keyed by ingredient id. A layer not named here always appears, which is why the whole dictionary is optional and null by default. It lives on the Recipe, and it could not live anywhere else. An .igt is a standalone file that a Kitchen hands to any project, so whether a Hat appears is not a property of the hat artwork — the same ingredient is guaranteed in one recipe and a chase item in another. This is the same shape CookBookManifest.RecipeWeights already uses one level up: a dictionary on the parent, keyed by the child's id. A percent, not a probability, and the unit is in the name. 0..1 would mean a conversion at every boundary a human touches — the CLI option, the form field, the report — and each one is a chance to divide by a hundred twice or not at all. This converts exactly once, in the roller. A chance, not an absent WEIGHT, because a weight is unstable: store one and then double every variant weight, and the layer silently gets commoner without anyone touching it. A chance survives variant edits, which is what an author means by "15% of the time". 100 means the layer never appears — shelved without deleting, the same thing a recipe weight of 0 already means one level up. Added after schemaVersion 1 and therefore OPTIONAL with a null default, for the same reasons spelled out on CookBookManifest.TargetSupply: Schema.Current is deliberately NOT bumped.
  • PartialAlpha (bool) - Whether any variant under this manifest carries a partial-alpha pixel — the book-level value is what the UI calls "2D only". A listing cache: writers stamp it from the pixels on every write, and anything that decoded the pixels recomputes it rather than reading it.

Properties

AbsentPercent

public IReadOnlyDictionary<string, double>? AbsentPercent { get; init; }

How often each layer is left out entirely, as a PERCENT, keyed by ingredient id. A layer not named here always appears, which is why the whole dictionary is optional and null by default.

It lives on the Recipe, and it could not live anywhere else. An .igt is a standalone file that a Kitchen hands to any project, so whether a Hat appears is not a property of the hat artwork — the same ingredient is guaranteed in one recipe and a chase item in another. This is the same shape CookBookManifest.RecipeWeights already uses one level up: a dictionary on the parent, keyed by the child's id.

A percent, not a probability, and the unit is in the name. 0..1 would mean a conversion at every boundary a human touches — the CLI option, the form field, the report — and each one is a chance to divide by a hundred twice or not at all. This converts exactly once, in the roller.

A chance, not an absent WEIGHT, because a weight is unstable: store one and then double every variant weight, and the layer silently gets commoner without anyone touching it. A chance survives variant edits, which is what an author means by "15% of the time".

100 means the layer never appears — shelved without deleting, the same thing a recipe weight of 0 already means one level up. Added after schemaVersion 1 and therefore OPTIONAL with a null default, for the same reasons spelled out on CookBookManifest.TargetSupply: Schema.Current is deliberately NOT bumped.

HasOptionalLayers

public bool HasOptionalLayers { get; }

Whether any layer of this recipe can be left out. This is what the GUI's "optional layers" toggle reads: the toggle is DERIVED from the data rather than stored beside it, so the two can never disagree about whether the feature is on.

Id

public string Id { get; init; }

Stable identifier, unique within its CookBook.

LayerOrder

public IReadOnlyList<string> LayerOrder { get; init; }

Ingredient ids bottom-to-top. This — not the ingredient collection's own order — is what generation rolls and composites, so an ingredient missing from it is never drawn.

Name

public string Name { get; init; }

Display name.

PartialAlpha

public bool PartialAlpha { get; init; }

Whether any variant under this manifest carries a partial-alpha pixel — the book-level value is what the UI calls "2D only". A listing cache: writers stamp it from the pixels on every write, and anything that decoded the pixels recomputes it rather than reading it.

Rules

public IReadOnlyList<IncompatibilityRule> Rules { get; init; }

Incompatibility rules applied to a rolled selection; a violation costs a re-roll.

SchemaVersion

public int SchemaVersion { get; init; }

The manifest format version; see Schema.

Methods

AbsentPercentOf(string)

public double AbsentPercentOf(string ingredientId);

How often one layer is left out, as a percent. Zero for a layer that always appears, which is every layer of a recipe that does not use the feature.

Parameters

  • ingredientId (string) - The layer to ask about.

Returns. 0..100.