#pragma once #include "CoreMinimal.h" #include "Core/DescentHandle.h" #include "Core/DescentWorldSubsystem.h" #include "DescentCraft.generated.h" /** Fabricator recipes (M7, DESIGN_UE.md section 6.7) as plain data. */ namespace Descent::Craft { enum ERes : int32 { Ingot = 0, Wafer, Lattice, Ferrite, Cobalt, NumRes }; THEDESCENT_API FString ResName(int32 Res); struct FRecipe { FName Id, Cat; FString Name, Desc; int32 Cost[NumRes] = { 0, 0, 0, 0, 0 }; FName Needs; // another recipe that must be built first bool bRepeatable = false; bool bLocked = false; // the weapon row FName Kit; // BUILD category: the kit it gives FName Item; // the inventory item it gives ... int32 ItemCount = 0; // ... and how many }; THEDESCENT_API const TArray& Recipes(); THEDESCENT_API const FRecipe* Find(FName Id); /** Takes exactly the cost from Have, or nothing (returns false) when something is short. */ THEDESCENT_API bool Pay(const FRecipe& R, int32 Have[NumRes]); THEDESCENT_API FString ItemName(FName Item); } struct FDescentItemStack { FName Item; int32 Count = 0; }; /** Crafting, upgrades, the suit inventory and the hotbar (V8, V11). Fills the fabricator, PDA inventory and storage windows. */ UCLASS() class THEDESCENT_API UDescentCraftSubsystem : public UDescentWorldSubsystem { GENERATED_BODY() public: static UDescentCraftSubsystem* Get(const UWorld* World); virtual void OnWorldBeginPlay(UWorld& InWorld) override; virtual void Deinitialize() override; // ---- crafting ---- bool CanCraft(FName Id, FString* OutWhyNot = nullptr) const; bool Craft(FName Id, FString* OutWhyNot = nullptr); bool IsBuilding() const { return BuildTimer > 0.0; } bool Has(FName Recipe) const { return Done.Contains(Recipe); } /** Applies one finished recipe to the game (Tender upgrades, tanks, kits, items). */ void ApplyOne(FName Id, bool bFromLoad = false); TSet Done; int32 Crafted = 0; // ---- the suit inventory (24 cells) and the hotbar (9 slots) ---- TArray Slots; int32 Count(FName Item) const; bool AddItem(FName Item, int32 N); bool RemoveItem(FName Item, int32 N); FName Hotbar[9]; int32 HotbarSelected = 0; int32 PdaSelected = -1; bool AssignHotbar(int32 Slot1to9, FName Item); void SelectHotbar(int32 Slot1to9) { HotbarSelected = FMath::Clamp(Slot1to9 - 1, 0, 8); } FName SelectedItem() const { return Hotbar[HotbarSelected]; } void ResetAll(); void OpenFabricator(); void FillWindows(); private: void Step(double Dt); void GatherHave(int32 Have[Descent::Craft::NumRes]) const; double BuildTimer = 0.0, WindowTimer = 0.0; FDescentHandle StepHandle; };