diff --git a/AGRARIAN_DEVELOPMENT_ROADMAP.md b/AGRARIAN_DEVELOPMENT_ROADMAP.md index 68e725e..e340425 100644 --- a/AGRARIAN_DEVELOPMENT_ROADMAP.md +++ b/AGRARIAN_DEVELOPMENT_ROADMAP.md @@ -590,7 +590,9 @@ Target deliverable: A small group can join a server, spawn into one biome, gathe - [x] Add cooking placeholder if needed. Added replicated campfire cooking placeholder state, a native cookability check, and progress ratio helpers so later recipe UI and food systems have a stable hook. -- [ ] Add smoke/visual effect placeholder. +- [x] Add smoke/visual effect placeholder. Added a native campfire smoke + particle component placeholder that activates and hides with replicated fire + state, leaving final visual assets assignable later. - [x] Add replication. - [ ] Add persistence. - [x] Connect fire to body temperature. diff --git a/Docs/TechnicalDesignDocument.md b/Docs/TechnicalDesignDocument.md index 764c7eb..60d9010 100644 --- a/Docs/TechnicalDesignDocument.md +++ b/Docs/TechnicalDesignDocument.md @@ -297,6 +297,11 @@ enabled, `AAgrarianCampfire` advances `CookingProgressSeconds` toward `CookingSecondsRequired` on the server and exposes `CanCook` plus a normalized progress ratio for future recipe UI, food transformation, and interaction hooks. +Campfire visuals include an assetless `SmokeEffect` particle-system component +placeholder. It is attached above the fire, starts inactive, and follows the +same replicated lit-state visual update path as fire light intensity so final +smoke or ember assets can be assigned later without changing gameplay code. + 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_smoke_placeholder.py b/Scripts/verify_fire_smoke_placeholder.py new file mode 100644 index 0000000..a2d466a --- /dev/null +++ b/Scripts/verify_fire_smoke_placeholder.py @@ -0,0 +1,44 @@ +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] + +REQUIRED = { + ROOT / "Source" / "AgrarianGame" / "AgrarianCampfire.h": [ + "class UParticleSystemComponent;", + "TObjectPtr SmokeEffect;", + ], + ROOT / "Source" / "AgrarianGame" / "AgrarianCampfire.cpp": [ + "#include \"Particles/ParticleSystemComponent.h\"", + "SmokeEffect = CreateDefaultSubobject(TEXT(\"SmokeEffect\"));", + "SmokeEffect->bAutoActivate = false;", + "SmokeEffect->SetVisibility(false);", + "SmokeEffect->SetVisibility(bLit);", + "SmokeEffect->ActivateSystem();", + "SmokeEffect->DeactivateSystem();", + ], + ROOT / "AGRARIAN_DEVELOPMENT_ROADMAP.md": [ + "- [x] Add smoke/visual effect placeholder.", + ], + ROOT / "Docs" / "TechnicalDesignDocument.md": [ + "assetless `SmokeEffect` particle-system component", + ], +} + + +def main(): + missing = [] + for path, snippets in REQUIRED.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 SystemExit("Campfire smoke placeholder verification failed:\n" + "\n".join(missing)) + + print("PASS: campfire smoke placeholder is implemented and documented.") + + +if __name__ == "__main__": + main() diff --git a/Source/AgrarianGame/AgrarianCampfire.cpp b/Source/AgrarianGame/AgrarianCampfire.cpp index c075cc3..cc62d7c 100644 --- a/Source/AgrarianGame/AgrarianCampfire.cpp +++ b/Source/AgrarianGame/AgrarianCampfire.cpp @@ -4,6 +4,7 @@ #include "AgrarianGameCharacter.h" #include "AgrarianInventoryComponent.h" #include "AgrarianSurvivalComponent.h" +#include "Particles/ParticleSystemComponent.h" #include "Components/PointLightComponent.h" #include "Components/StaticMeshComponent.h" #include "Kismet/GameplayStatics.h" @@ -22,6 +23,12 @@ AAgrarianCampfire::AAgrarianCampfire() FireLight->SetIntensity(0.0f); FireLight->SetAttenuationRadius(WarmthRadius); FireLight->SetLightColor(FLinearColor(1.0f, 0.45f, 0.18f)); + + SmokeEffect = CreateDefaultSubobject(TEXT("SmokeEffect")); + SmokeEffect->SetupAttachment(RootComponent); + SmokeEffect->bAutoActivate = false; + SmokeEffect->SetRelativeLocation(FVector(0.0f, 0.0f, 80.0f)); + SmokeEffect->SetVisibility(false); } void AAgrarianCampfire::Tick(float DeltaSeconds) @@ -140,6 +147,19 @@ void AAgrarianCampfire::UpdateVisualState() { FireLight->SetIntensity(bLit ? 4200.0f : 0.0f); } + + if (SmokeEffect) + { + SmokeEffect->SetVisibility(bLit); + if (bLit) + { + SmokeEffect->ActivateSystem(); + } + else + { + SmokeEffect->DeactivateSystem(); + } + } } void AAgrarianCampfire::WarmNearbyCharacters(float DeltaSeconds) diff --git a/Source/AgrarianGame/AgrarianCampfire.h b/Source/AgrarianGame/AgrarianCampfire.h index 56b04ad..34e3c57 100644 --- a/Source/AgrarianGame/AgrarianCampfire.h +++ b/Source/AgrarianGame/AgrarianCampfire.h @@ -8,6 +8,7 @@ #include "AgrarianCampfire.generated.h" class UPointLightComponent; +class UParticleSystemComponent; class UStaticMeshComponent; UCLASS(Blueprintable) @@ -27,6 +28,9 @@ public: UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Fire") TObjectPtr FireLight; + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Agrarian|Fire|Effects") + TObjectPtr SmokeEffect; + UPROPERTY(EditAnywhere, BlueprintReadWrite, ReplicatedUsing = OnRep_FireState, Category = "Agrarian|Fire") bool bLit = false;