825c5d3c5c
01-RecipeData Rev 6 (A4) added the field as a Summarize-branch discriminator for module 02. Resolved as IsExpertRecipe OR the output item's AlwaysCollectable flag, the latter being the canonical FFXIV signal for collectable submissions (custom delivery, masterpiece supply, collectables shop). - AnvilRecipe.cs: new required bool property after CanHQ, with a why-comment pointing at module 02's Summarize branch and noting the OR-resolve. - LuminaRecipeAdapter.cs: resolve folded into the recipe walk via the same itemSheet.TryGetRow call that already fetches the display name - no bootstrap-order question, no 2-pass needed. hasOutputItem is hoisted so the OR-branch can guard against a missing item-sheet row without touching the default(Item) struct. - RecipeDataAdapterLoadStep.cs: new pass criterion #10 that asserts at least one recipe surfaces IsCollectable == true. Catches a silent resolve-path failure. Existing Cosmic-surface check shifts to #11 to keep numbering stable. Build clean (0/0), csharpier clean.
74 lines
3.7 KiB
C#
74 lines
3.7 KiB
C#
// Plain-data record describing a single FFXIV crafting recipe. Public surface
|
|
// is intentionally BCL-only (no Lumina or Dalamud types) so the simulator and
|
|
// solver can be tested in xUnit without loading Dalamud.dll into the test
|
|
// AppDomain. The adapter (Internal/LuminaRecipeAdapter) builds these from the
|
|
// Recipe + RecipeLevelTable sheet pair and flattens both sheets into one
|
|
// record so consumers never have to do a two-sheet walk.
|
|
|
|
using System.Collections.Generic;
|
|
|
|
namespace Anvil.RecipeData;
|
|
|
|
public sealed record AnvilRecipe
|
|
{
|
|
public required uint RecipeId { get; init; }
|
|
public required uint OutputItemId { get; init; }
|
|
public required byte OutputAmount { get; init; }
|
|
public required uint ClassJobId { get; init; }
|
|
public required ushort RecipeLevel { get; init; }
|
|
|
|
// Character-level equivalent of the recipe's difficulty (e.g. 90 for an
|
|
// Endwalker 3-star, 100 for a Dawntrail endgame recipe). Not the same as
|
|
// RecipeLevel above - that field is the RecipeLevelTable row id, this one
|
|
// is its ClassJobLevel column. Module 02 uses it for the mod-penalty
|
|
// branch in BaseProgress and BaseQuality.
|
|
public required byte RecipeLevelTableClassJobLevel { get; init; }
|
|
|
|
public required int Difficulty { get; init; }
|
|
public required int QualityMax { get; init; }
|
|
public required byte Durability { get; init; }
|
|
public required int RequiredCraftsmanship { get; init; }
|
|
public required int RequiredControl { get; init; }
|
|
public required int QualityForHQ { get; init; }
|
|
public required bool IsExpertRecipe { get; init; }
|
|
public required bool CanHQ { get; init; }
|
|
|
|
// True when the recipe is a collectable submission (custom delivery,
|
|
// masterpiece supply, collectables shop). Module 02's Summarize branch
|
|
// uses this discriminator. Resolved as IsExpertRecipe OR the output
|
|
// item's AlwaysCollectable flag - the latter is the canonical FFXIV
|
|
// signal for collectable submissions.
|
|
public required bool IsCollectable { get; init; }
|
|
|
|
// Cosmic Exploration (Patch 7.x). v0.1.0 ships with MissionHas* always
|
|
// false (SH-15 option B) - the data schema stays in place so v0.2.0+ can
|
|
// light up the surface by resolving the WKS mission sheet without
|
|
// touching the type. IsCosmic is still set by the recipe-detection path
|
|
// so the catalog knows which recipes belong to the Cosmic surface even
|
|
// while the mission flags stay dormant. The Splendorous-tool bonus is
|
|
// character-equipment state rather than recipe state, so it lives in
|
|
// the simulator's stats layer (CraftStats.HasSplendorousTool in module
|
|
// 02) instead of carrying a flag on this record.
|
|
//
|
|
// Adapter invariant (validated when the catalog is built):
|
|
// MissionHasMaterialMiracle == true implies IsCosmic == true
|
|
// MissionHasSteadyHand == true implies IsCosmic == true
|
|
//
|
|
// Inconsistent recipe states (sub-flag without master flag) throw at
|
|
// catalog-build time instead of silently corrupting the simulator.
|
|
public required bool IsCosmic { get; init; }
|
|
public required bool MissionHasMaterialMiracle { get; init; }
|
|
public required bool MissionHasSteadyHand { get; init; }
|
|
public required bool IsIshgardExpert { get; init; }
|
|
|
|
public required byte Stars { get; init; }
|
|
public required byte ProgressDivider { get; init; }
|
|
public required byte ProgressModifier { get; init; }
|
|
public required byte QualityDivider { get; init; }
|
|
public required byte QualityModifier { get; init; }
|
|
public required IReadOnlyList<AnvilRecipeIngredient> Ingredients { get; init; }
|
|
public required string DisplayName { get; init; }
|
|
}
|
|
|
|
public sealed record AnvilRecipeIngredient(uint ItemId, byte Amount);
|