12013ba6e6
01-RecipeData Rev 6 (A1) added the field as the character-level equivalent of a recipe's RecipeLevelTable, so module 02 can branch the mod-penalty in BaseProgress and BaseQuality. The adapter resolves it from the existing RecipeLevelTable.Value in the recipe walk. - AnvilRecipe.cs: new required byte property after RecipeLevel, with a why-comment that points consumers at module 02 and warns against confusing the field with the row-id one above it. - LuminaRecipeAdapter.cs: levelTable.ClassJobLevel assignment in the Recipe walk - levelTable was already resolved earlier in the loop. - RecipeDataAdapterLoadStep.cs: new pass criterion #9 that asserts at least one recipe carries a positive RecipeLevelTableClassJobLevel. Catches a silent RecipeLevelTable-walk failure that would otherwise only surface inside the simulator. Existing Cosmic-surface check shifted to #10 to keep the spec numbering stable. Build clean (0/0), csharpier clean.
67 lines
3.3 KiB
C#
67 lines
3.3 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; }
|
|
|
|
// 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);
|