diff --git a/AGRARIAN_DEVELOPMENT_ROADMAP.md b/AGRARIAN_DEVELOPMENT_ROADMAP.md index 8f7d245..925d22e 100644 --- a/AGRARIAN_DEVELOPMENT_ROADMAP.md +++ b/AGRARIAN_DEVELOPMENT_ROADMAP.md @@ -582,7 +582,9 @@ Target deliverable: A small group can join a server, spawn into one biome, gathe - [x] Create fire actor. - [x] Add fuel amount. - [x] Add ignition interaction. -- [ ] Add extinguish logic. +- [x] Add extinguish logic. Added native campfire extinguish support that + clears fuel, turns off replicated lit state, and reuses the fire visual + update path used by natural fuel depletion. - [x] Add warmth radius. - [x] Add light source. - [ ] Add cooking placeholder if needed. diff --git a/Docs/TechnicalDesignDocument.md b/Docs/TechnicalDesignDocument.md index 3f27c0f..ea52f9d 100644 --- a/Docs/TechnicalDesignDocument.md +++ b/Docs/TechnicalDesignDocument.md @@ -288,6 +288,10 @@ controller is silent until loops are assigned; placeholder or final audio can be added by setting the exposed sound properties on the placed controller or a Blueprint child. +Campfires expose native extinguish logic through `AAgrarianCampfire::Extinguish`. +Extinguishing clears remaining fuel, turns off replicated lit state, and reuses +the same visual update path as natural fuel depletion. + The first real-weather adapter is `UAgrarianWeatherProviderSubsystem`. It uses Open-Meteo forecast requests keyed by tile center latitude/longitude, parses the current temperature, daily low/high, precipitation, wind, humidity, cloud cover, diff --git a/Scripts/verify_fire_extinguish_logic.py b/Scripts/verify_fire_extinguish_logic.py new file mode 100644 index 0000000..a18ceac --- /dev/null +++ b/Scripts/verify_fire_extinguish_logic.py @@ -0,0 +1,42 @@ +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] + +EXPECTED = { + ROOT / "Source" / "AgrarianGame" / "AgrarianCampfire.h": [ + "void Extinguish();", + "void SetLit(bool bNewLit);", + ], + ROOT / "Source" / "AgrarianGame" / "AgrarianCampfire.cpp": [ + "void AAgrarianCampfire::Extinguish()", + "FuelSeconds = 0.0f;", + "SetLit(false);", + "void AAgrarianCampfire::SetLit(bool bNewLit)", + "UpdateVisualState();", + ], + ROOT / "Docs" / "TechnicalDesignDocument.md": [ + "Campfires expose native extinguish logic", + ], + ROOT / "AGRARIAN_DEVELOPMENT_ROADMAP.md": [ + "- [x] Add extinguish logic.", + ], +} + + +def main(): + missing = [] + for path, snippets in EXPECTED.items(): + text = path.read_text(encoding="utf-8") + for snippet in snippets: + if snippet not in text: + missing.append(f"{path.relative_to(ROOT)} missing {snippet!r}") + + if missing: + raise RuntimeError("Fire extinguish verification failed: " + "; ".join(missing)) + + print("PASS: campfire extinguish logic is implemented and documented.") + + +if __name__ == "__main__": + main() diff --git a/Source/AgrarianGame/AgrarianCampfire.cpp b/Source/AgrarianGame/AgrarianCampfire.cpp index 006e2a3..b28ae13 100644 --- a/Source/AgrarianGame/AgrarianCampfire.cpp +++ b/Source/AgrarianGame/AgrarianCampfire.cpp @@ -33,8 +33,7 @@ void AAgrarianCampfire::Tick(float DeltaSeconds) FuelSeconds = FMath::Max(0.0f, FuelSeconds - DeltaSeconds); if (FuelSeconds <= 0.0f) { - bLit = false; - UpdateVisualState(); + SetLit(false); } WarmNearbyCharacters(DeltaSeconds); @@ -69,8 +68,6 @@ void AAgrarianCampfire::Interact_Implementation(AAgrarianGameCharacter* Interact if (Inventory && Inventory->RemoveItem(TEXT("wood"), 1)) { AddFuel(90.0f); - bLit = true; - UpdateVisualState(); } } @@ -81,9 +78,21 @@ void AAgrarianCampfire::AddFuel(float Seconds) FuelSeconds += FMath::Max(0.0f, Seconds); if (FuelSeconds > 0.0f) { - bLit = true; + SetLit(true); } - UpdateVisualState(); + else + { + UpdateVisualState(); + } + } +} + +void AAgrarianCampfire::Extinguish() +{ + if (HasAuthority()) + { + FuelSeconds = 0.0f; + SetLit(false); } } @@ -92,6 +101,16 @@ void AAgrarianCampfire::OnRep_FireState() UpdateVisualState(); } +void AAgrarianCampfire::SetLit(bool bNewLit) +{ + if (bLit != bNewLit) + { + bLit = bNewLit; + } + + UpdateVisualState(); +} + void AAgrarianCampfire::UpdateVisualState() { if (FireLight) diff --git a/Source/AgrarianGame/AgrarianCampfire.h b/Source/AgrarianGame/AgrarianCampfire.h index 6be9cfb..b36c5e1 100644 --- a/Source/AgrarianGame/AgrarianCampfire.h +++ b/Source/AgrarianGame/AgrarianCampfire.h @@ -46,10 +46,14 @@ public: UFUNCTION(BlueprintCallable, Category = "Agrarian|Fire") void AddFuel(float Seconds); + UFUNCTION(BlueprintCallable, Category = "Agrarian|Fire") + void Extinguish(); + protected: UFUNCTION() void OnRep_FireState(); + void SetLit(bool bNewLit); void UpdateVisualState(); void WarmNearbyCharacters(float DeltaSeconds); };