Connect campfires to weather
This commit is contained in:
@@ -598,7 +598,9 @@ Target deliverable: A small group can join a server, spawn into one biome, gathe
|
|||||||
lit state, fuel seconds, and cooking placeholder progress using the shared
|
lit state, fuel seconds, and cooking placeholder progress using the shared
|
||||||
world-actor persistence path.
|
world-actor persistence path.
|
||||||
- [x] Connect fire to body temperature.
|
- [x] Connect fire to body temperature.
|
||||||
- [ ] Connect rain/weather to fire behavior.
|
- [x] Connect rain/weather to fire behavior. Campfires now read replicated
|
||||||
|
game-state weather, burn fuel faster in rain and storms, and deterministically
|
||||||
|
extinguish when wet weather pushes remaining fuel below the low-fuel threshold.
|
||||||
|
|
||||||
## 0.1.I Shelter Building
|
## 0.1.I Shelter Building
|
||||||
|
|
||||||
|
|||||||
@@ -308,6 +308,12 @@ to write lit state, remaining fuel, cooking enabled state, required cook time,
|
|||||||
and cooking progress into numeric save state, then restores those values before
|
and cooking progress into numeric save state, then restores those values before
|
||||||
reapplying the fire visual state on load.
|
reapplying the fire visual state on load.
|
||||||
|
|
||||||
|
Campfires now read the replicated `AAgrarianGameState::Weather` value while
|
||||||
|
burning. Rain and storms increase fuel drain through tunable multipliers, and
|
||||||
|
wet weather can deterministically extinguish a low-fuel fire so weather affects
|
||||||
|
fire reliability without adding random outcomes to save/load or multiplayer
|
||||||
|
state.
|
||||||
|
|
||||||
The first real-weather adapter is `UAgrarianWeatherProviderSubsystem`. It uses
|
The first real-weather adapter is `UAgrarianWeatherProviderSubsystem`. It uses
|
||||||
Open-Meteo forecast requests keyed by tile center latitude/longitude, parses the
|
Open-Meteo forecast requests keyed by tile center latitude/longitude, parses the
|
||||||
current temperature, daily low/high, precipitation, wind, humidity, cloud cover,
|
current temperature, daily low/high, precipitation, wind, humidity, cloud cover,
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
|
||||||
|
REQUIRED = {
|
||||||
|
ROOT / "Source" / "AgrarianGame" / "AgrarianCampfire.h": [
|
||||||
|
"#include \"AgrarianTypes.h\"",
|
||||||
|
"float RainFuelDrainMultiplier = 1.5f;",
|
||||||
|
"float StormFuelDrainMultiplier = 2.5f;",
|
||||||
|
"float WetWeatherExtinguishFuelThresholdSeconds = 6.0f;",
|
||||||
|
"bool bWetWeatherCanExtinguish = true;",
|
||||||
|
"float GetWeatherFuelDrainMultiplier() const;",
|
||||||
|
"bool IsWetWeatherActive() const;",
|
||||||
|
"EAgrarianWeatherType GetCurrentWeather() const;",
|
||||||
|
],
|
||||||
|
ROOT / "Source" / "AgrarianGame" / "AgrarianCampfire.cpp": [
|
||||||
|
"#include \"AgrarianGameState.h\"",
|
||||||
|
"DeltaSeconds * GetWeatherFuelDrainMultiplier()",
|
||||||
|
"bWetWeatherCanExtinguish && IsWetWeatherActive()",
|
||||||
|
"WetWeatherExtinguishFuelThresholdSeconds",
|
||||||
|
"Extinguish();",
|
||||||
|
"case EAgrarianWeatherType::Rain:",
|
||||||
|
"case EAgrarianWeatherType::Storm:",
|
||||||
|
"World->GetGameState<AAgrarianGameState>()",
|
||||||
|
"return EAgrarianWeatherType::Clear;",
|
||||||
|
],
|
||||||
|
ROOT / "AGRARIAN_DEVELOPMENT_ROADMAP.md": [
|
||||||
|
"- [x] Connect rain/weather to fire behavior.",
|
||||||
|
],
|
||||||
|
ROOT / "Docs" / "TechnicalDesignDocument.md": [
|
||||||
|
"Campfires now read the replicated `AAgrarianGameState::Weather` value",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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 weather behavior verification failed:\n" + "\n".join(missing))
|
||||||
|
|
||||||
|
print("PASS: campfire weather behavior is implemented and documented.")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "AgrarianCampfire.h"
|
#include "AgrarianCampfire.h"
|
||||||
#include "AgrarianGameCharacter.h"
|
#include "AgrarianGameCharacter.h"
|
||||||
|
#include "AgrarianGameState.h"
|
||||||
#include "AgrarianInventoryComponent.h"
|
#include "AgrarianInventoryComponent.h"
|
||||||
#include "AgrarianPersistentActorComponent.h"
|
#include "AgrarianPersistentActorComponent.h"
|
||||||
#include "AgrarianSurvivalComponent.h"
|
#include "AgrarianSurvivalComponent.h"
|
||||||
@@ -41,10 +42,10 @@ void AAgrarianCampfire::Tick(float DeltaSeconds)
|
|||||||
|
|
||||||
if (HasAuthority() && bLit)
|
if (HasAuthority() && bLit)
|
||||||
{
|
{
|
||||||
FuelSeconds = FMath::Max(0.0f, FuelSeconds - DeltaSeconds);
|
FuelSeconds = FMath::Max(0.0f, FuelSeconds - (DeltaSeconds * GetWeatherFuelDrainMultiplier()));
|
||||||
if (FuelSeconds <= 0.0f)
|
if (FuelSeconds <= 0.0f || (bWetWeatherCanExtinguish && IsWetWeatherActive() && FuelSeconds <= WetWeatherExtinguishFuelThresholdSeconds))
|
||||||
{
|
{
|
||||||
SetLit(false);
|
Extinguish();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CanCook())
|
if (CanCook())
|
||||||
@@ -180,11 +181,43 @@ float AAgrarianCampfire::GetCookingProgressRatio() const
|
|||||||
return FMath::Clamp(CookingProgressSeconds / CookingSecondsRequired, 0.0f, 1.0f);
|
return FMath::Clamp(CookingProgressSeconds / CookingSecondsRequired, 0.0f, 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float AAgrarianCampfire::GetWeatherFuelDrainMultiplier() const
|
||||||
|
{
|
||||||
|
switch (GetCurrentWeather())
|
||||||
|
{
|
||||||
|
case EAgrarianWeatherType::Rain:
|
||||||
|
return FMath::Max(1.0f, RainFuelDrainMultiplier);
|
||||||
|
case EAgrarianWeatherType::Storm:
|
||||||
|
return FMath::Max(1.0f, StormFuelDrainMultiplier);
|
||||||
|
default:
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AAgrarianCampfire::IsWetWeatherActive() const
|
||||||
|
{
|
||||||
|
const EAgrarianWeatherType CurrentWeather = GetCurrentWeather();
|
||||||
|
return CurrentWeather == EAgrarianWeatherType::Rain || CurrentWeather == EAgrarianWeatherType::Storm;
|
||||||
|
}
|
||||||
|
|
||||||
void AAgrarianCampfire::OnRep_FireState()
|
void AAgrarianCampfire::OnRep_FireState()
|
||||||
{
|
{
|
||||||
UpdateVisualState();
|
UpdateVisualState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EAgrarianWeatherType AAgrarianCampfire::GetCurrentWeather() const
|
||||||
|
{
|
||||||
|
if (const UWorld* World = GetWorld())
|
||||||
|
{
|
||||||
|
if (const AAgrarianGameState* GameState = World->GetGameState<AAgrarianGameState>())
|
||||||
|
{
|
||||||
|
return GameState->Weather;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return EAgrarianWeatherType::Clear;
|
||||||
|
}
|
||||||
|
|
||||||
void AAgrarianCampfire::SetLit(bool bNewLit)
|
void AAgrarianCampfire::SetLit(bool bNewLit)
|
||||||
{
|
{
|
||||||
if (bLit != bNewLit)
|
if (bLit != bNewLit)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "GameFramework/Actor.h"
|
#include "GameFramework/Actor.h"
|
||||||
#include "AgrarianInteractable.h"
|
#include "AgrarianInteractable.h"
|
||||||
#include "AgrarianPersistentStateProvider.h"
|
#include "AgrarianPersistentStateProvider.h"
|
||||||
|
#include "AgrarianTypes.h"
|
||||||
#include "AgrarianCampfire.generated.h"
|
#include "AgrarianCampfire.generated.h"
|
||||||
|
|
||||||
class UPointLightComponent;
|
class UPointLightComponent;
|
||||||
@@ -57,6 +58,18 @@ public:
|
|||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Replicated, Category = "Agrarian|Fire|Cooking", meta = (ClampMin = "0"))
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Replicated, Category = "Agrarian|Fire|Cooking", meta = (ClampMin = "0"))
|
||||||
float CookingProgressSeconds = 0.0f;
|
float CookingProgressSeconds = 0.0f;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Fire|Weather", meta = (ClampMin = "1"))
|
||||||
|
float RainFuelDrainMultiplier = 1.5f;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Fire|Weather", meta = (ClampMin = "1"))
|
||||||
|
float StormFuelDrainMultiplier = 2.5f;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Fire|Weather", meta = (ClampMin = "0"))
|
||||||
|
float WetWeatherExtinguishFuelThresholdSeconds = 6.0f;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Fire|Weather")
|
||||||
|
bool bWetWeatherCanExtinguish = true;
|
||||||
|
|
||||||
virtual FText GetInteractionText_Implementation(const AAgrarianGameCharacter* Interactor) const override;
|
virtual FText GetInteractionText_Implementation(const AAgrarianGameCharacter* Interactor) const override;
|
||||||
virtual bool CanInteract_Implementation(const AAgrarianGameCharacter* Interactor) const override;
|
virtual bool CanInteract_Implementation(const AAgrarianGameCharacter* Interactor) const override;
|
||||||
virtual void Interact_Implementation(AAgrarianGameCharacter* Interactor) override;
|
virtual void Interact_Implementation(AAgrarianGameCharacter* Interactor) override;
|
||||||
@@ -75,10 +88,17 @@ public:
|
|||||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Agrarian|Fire|Cooking")
|
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Agrarian|Fire|Cooking")
|
||||||
float GetCookingProgressRatio() const;
|
float GetCookingProgressRatio() const;
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Agrarian|Fire|Weather")
|
||||||
|
float GetWeatherFuelDrainMultiplier() const;
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Agrarian|Fire|Weather")
|
||||||
|
bool IsWetWeatherActive() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
UFUNCTION()
|
UFUNCTION()
|
||||||
void OnRep_FireState();
|
void OnRep_FireState();
|
||||||
|
|
||||||
|
EAgrarianWeatherType GetCurrentWeather() const;
|
||||||
void SetLit(bool bNewLit);
|
void SetLit(bool bNewLit);
|
||||||
void UpdateVisualState();
|
void UpdateVisualState();
|
||||||
void WarmNearbyCharacters(float DeltaSeconds);
|
void WarmNearbyCharacters(float DeltaSeconds);
|
||||||
|
|||||||
Reference in New Issue
Block a user