## Summary Adopts ModernUO.Serialization 4.0.0 across the engine. Three commits, reviewable independently: 1. **Package + tool bump to 4.0.0** (`Server.csproj`, `UOContent.csproj`, `dotnet-tools.json`). 2. **Timers → `[DeserializeTimer]`** — the 8 drifting timers (BaseLight, TreasureMapChest, MarkContainer, FillableContainer, DeathRobe, DecayedCorpse, Corpse, BaseEscortable) now store their next tick as **anchored time**: server downtime no longer consumes the remaining delay, and idle-world saves are byte-stable. This changes their wire format, so each class bumps its serialization version with a `MigrateFrom` that replays the old delta-time read through the migration schema (the new `vN.json` files carry `@AnchoredTimer`; the old ones keep `@TimerDrift`, which the generator reads forever). The 2 wall-clock timers (Aquarium, FountainOfLife) keep their exact format via `wallClock: true` — no bump. Restart methods drop their `TimeSpan.MinValue` sentinel checks: v4 invokes them **only when a timer was actually running at save**. 3. **Linkage → field-side declarations** — 175 conversions across 25 files: `[SerializableFieldSaveFlag(order)]`/`[SerializableFieldDefault(order)]` become `[SaveFlag(nameof(...), nameof(...))]` on the field, and `[SerializableFieldChanged(order)]` becomes the `fieldChanged:` argument of `[SerializableField]`. **Wire-neutral: zero migration schemas changed.** ## Verification - Solution builds with **0 errors, 0 warnings**; all three 4.0.0 packages verified indexed on nuget.org (no local feed needed). - **835 + 708 tests green.** - Generated output inspected: old-version content structs replay `ReadDeltaTime` (e.g. `V3Content.DecayTimerNext = reader.ReadDeltaTime()`), current versions write/read anchored time with the gated restart, and the wall-clock classes emit byte-identical `Write`/`ReadDateTime` framing. - Schema tool run is committed (CI's `git diff --exit-code` schema check passes): exactly the 8 expected new `vN.json` files, nothing else touched. - The conversion was scripted with a class-scoped resolver (order → same-class `[SerializableField(order)]`/`[SerializableProperty(order)]`); it planned 175/175 with zero ambiguities before applying. ## Notes - New `MigrateFrom`s use the content structs' provided `XxxDelay` property, matching the pre-existing idiom in Corpse's and TreasureMapChest's older migrations. - Follow-up candidate (separate PR, wire-neutral, any time): fold the ~150 eligible hand-written `[SerializableProperty]` setters (clamps, post-change side effects) down to `[SerializableField]` with `allowFieldChange`/`fieldChanged` hooks.
730 lines
20 KiB
C#
730 lines
20 KiB
C#
using System;
|
|
using ModernUO.CodeGeneratedEvents;
|
|
using ModernUO.Serialization;
|
|
using Server.Misc;
|
|
using Server.Mobiles;
|
|
|
|
namespace Server.Engines.Plants
|
|
{
|
|
public enum PlantHealth
|
|
{
|
|
Dying,
|
|
Wilted,
|
|
Healthy,
|
|
Vibrant
|
|
}
|
|
|
|
public enum PlantGrowthIndicator
|
|
{
|
|
None,
|
|
InvalidLocation,
|
|
NotHealthy,
|
|
Delay,
|
|
Grown,
|
|
DoubleGrown
|
|
}
|
|
|
|
[SerializationGenerator(3, false)]
|
|
public partial class PlantSystem
|
|
{
|
|
public static readonly TimeSpan CheckDelay = TimeSpan.FromHours(23.0);
|
|
|
|
[DirtyTrackingEntity]
|
|
private PlantItem _plant;
|
|
|
|
[SerializableField(0)]
|
|
[SaveFlag(nameof(ShouldSerializeFertileDirt))]
|
|
private bool _fertileDirt;
|
|
|
|
private bool ShouldSerializeFertileDirt() => _fertileDirt;
|
|
|
|
[SerializableField(1)]
|
|
private DateTime _nextGrowth;
|
|
|
|
[SerializableField(2, setter: "private")]
|
|
[SaveFlag(nameof(ShouldSerializeGrowthIndicator))]
|
|
private PlantGrowthIndicator _growthIndicator;
|
|
|
|
private bool ShouldSerializeGrowthIndicator() => _growthIndicator != PlantGrowthIndicator.None;
|
|
|
|
[SerializableField(13)]
|
|
[SaveFlag(nameof(ShouldSerializePollinated))]
|
|
private bool _pollinated;
|
|
|
|
private bool ShouldSerializePollinated() => _pollinated;
|
|
|
|
public PlantSystem(PlantItem plant)
|
|
{
|
|
_plant = plant;
|
|
|
|
_nextGrowth = Core.Now + CheckDelay;
|
|
_growthIndicator = PlantGrowthIndicator.None;
|
|
_hits = MaxHits;
|
|
_leftSeeds = 8;
|
|
_leftResources = 8;
|
|
}
|
|
|
|
private void Deserialize(IGenericReader reader, int version)
|
|
{
|
|
_fertileDirt = reader.ReadBool();
|
|
_nextGrowth = reader.ReadDateTime();
|
|
|
|
_growthIndicator = (PlantGrowthIndicator)reader.ReadInt();
|
|
|
|
_water = reader.ReadInt();
|
|
|
|
_hits = reader.ReadInt();
|
|
_infestation = reader.ReadInt();
|
|
_fungus = reader.ReadInt();
|
|
_poison = reader.ReadInt();
|
|
_disease = reader.ReadInt();
|
|
_poisonPotion = reader.ReadInt();
|
|
_curePotion = reader.ReadInt();
|
|
_healPotion = reader.ReadInt();
|
|
_strengthPotion = reader.ReadInt();
|
|
|
|
Pollinated = reader.ReadBool();
|
|
_seedType = (PlantType)reader.ReadInt();
|
|
_seedHue = (PlantHue)reader.ReadInt();
|
|
_availableSeeds = reader.ReadInt();
|
|
_leftSeeds = reader.ReadInt();
|
|
|
|
_availableResources = reader.ReadInt();
|
|
_leftResources = reader.ReadInt();
|
|
}
|
|
|
|
public PlantItem Plant => _plant;
|
|
|
|
public bool IsFullWater => _water >= 4;
|
|
|
|
[SerializableProperty(3)]
|
|
[SaveFlag(nameof(ShouldSerializeWater))]
|
|
public int Water
|
|
{
|
|
get => _water;
|
|
set
|
|
{
|
|
_water = Math.Clamp(value, 0, 4);
|
|
Plant.InvalidateProperties();
|
|
MarkDirty();
|
|
}
|
|
}
|
|
|
|
private bool ShouldSerializeWater() => _water != 0;
|
|
|
|
[SerializableProperty(4)]
|
|
[SaveFlag(nameof(ShouldSerializeHits))]
|
|
public int Hits
|
|
{
|
|
get => _hits;
|
|
set
|
|
{
|
|
if (_hits == value)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_hits = Math.Clamp(value, 0, MaxHits);
|
|
|
|
if (_hits == 0)
|
|
{
|
|
Plant.Die();
|
|
}
|
|
|
|
Plant.InvalidateProperties();
|
|
MarkDirty();
|
|
}
|
|
}
|
|
|
|
private bool ShouldSerializeHits() => _hits != 0;
|
|
|
|
public int MaxHits => 10 + (int)Plant.PlantStatus * 2;
|
|
|
|
public PlantHealth Health =>
|
|
(_hits * 100 / MaxHits) switch
|
|
{
|
|
< 33 => PlantHealth.Dying,
|
|
< 66 => PlantHealth.Wilted,
|
|
< 100 => PlantHealth.Healthy,
|
|
_ => PlantHealth.Vibrant
|
|
};
|
|
|
|
[SerializableProperty(5)]
|
|
[SaveFlag(nameof(ShouldSerializeInfestation))]
|
|
public int Infestation
|
|
{
|
|
get => _infestation;
|
|
set
|
|
{
|
|
_infestation = Math.Clamp(value, 0, 2);
|
|
MarkDirty();
|
|
}
|
|
}
|
|
|
|
private bool ShouldSerializeInfestation() => _infestation != 0;
|
|
|
|
[SerializableProperty(6)]
|
|
[SaveFlag(nameof(ShouldSerializeFungus))]
|
|
public int Fungus
|
|
{
|
|
get => _fungus;
|
|
set
|
|
{
|
|
_fungus = Math.Clamp(value, 0, 2);
|
|
MarkDirty();
|
|
}
|
|
}
|
|
|
|
private bool ShouldSerializeFungus() => _fungus != 0;
|
|
|
|
[SerializableProperty(7)]
|
|
[SaveFlag(nameof(ShouldSerializePoison))]
|
|
public int Poison
|
|
{
|
|
get => _poison;
|
|
set
|
|
{
|
|
_poison = Math.Clamp(value, 0, 2);
|
|
MarkDirty();
|
|
}
|
|
}
|
|
|
|
private bool ShouldSerializePoison() => _poison != 0;
|
|
|
|
[SerializableProperty(8)]
|
|
[SaveFlag(nameof(ShouldSerializeDisease))]
|
|
public int Disease
|
|
{
|
|
get => _disease;
|
|
set
|
|
{
|
|
_disease = Math.Clamp(value, 0, 2);
|
|
MarkDirty();
|
|
}
|
|
}
|
|
|
|
private bool ShouldSerializeDisease() => _disease != 0;
|
|
|
|
public bool IsFullPoisonPotion => _poisonPotion >= 2;
|
|
|
|
[SerializableProperty(9)]
|
|
[SaveFlag(nameof(ShouldSerializePoisonPotion))]
|
|
public int PoisonPotion
|
|
{
|
|
get => _poisonPotion;
|
|
set
|
|
{
|
|
_poisonPotion = Math.Clamp(value, 0, 2);
|
|
MarkDirty();
|
|
}
|
|
}
|
|
|
|
private bool ShouldSerializePoisonPotion() => _poisonPotion != 0;
|
|
|
|
public bool IsFullCurePotion => _curePotion >= 2;
|
|
|
|
[SerializableProperty(10)]
|
|
[SaveFlag(nameof(ShouldSerializeCurePotion))]
|
|
public int CurePotion
|
|
{
|
|
get => _curePotion;
|
|
set
|
|
{
|
|
_curePotion = Math.Clamp(value, 0, 2);
|
|
MarkDirty();
|
|
}
|
|
}
|
|
|
|
private bool ShouldSerializeCurePotion() => _curePotion != 0;
|
|
|
|
public bool IsFullHealPotion => _healPotion >= 2;
|
|
|
|
[SerializableProperty(11)]
|
|
[SaveFlag(nameof(ShouldSerializeHealPotion))]
|
|
public int HealPotion
|
|
{
|
|
get => _healPotion;
|
|
set
|
|
{
|
|
_healPotion = Math.Clamp(value, 0, 2);
|
|
MarkDirty();
|
|
}
|
|
}
|
|
|
|
private bool ShouldSerializeHealPotion() => _healPotion != 0;
|
|
|
|
public bool IsFullStrengthPotion => _strengthPotion >= 2;
|
|
|
|
[SerializableProperty(12)]
|
|
[SaveFlag(nameof(ShouldSerializeStrengthPotion))]
|
|
public int StrengthPotion
|
|
{
|
|
get => _strengthPotion;
|
|
set
|
|
{
|
|
_strengthPotion = Math.Clamp(value, 0, 2);
|
|
MarkDirty();
|
|
}
|
|
}
|
|
|
|
private bool ShouldSerializeStrengthPotion() => _strengthPotion != 0;
|
|
|
|
public bool HasMaladies => Infestation > 0 || Fungus > 0 || Poison > 0 || Disease > 0 || Water != 2;
|
|
|
|
public bool PollenProducing => Plant.IsCrossable && Plant.PlantStatus >= PlantStatus.FullGrownPlant;
|
|
|
|
[SerializableProperty(14)]
|
|
[SaveFlag(nameof(ShouldSerializeSeedType))]
|
|
public PlantType SeedType
|
|
{
|
|
get => Pollinated ? _seedType : Plant.PlantType;
|
|
set
|
|
{
|
|
_seedType = value;
|
|
MarkDirty();
|
|
}
|
|
}
|
|
|
|
private bool ShouldSerializeSeedType() => _pollinated;
|
|
|
|
[SerializableProperty(15)]
|
|
[SaveFlag(nameof(ShouldSerializeSeedHue))]
|
|
public PlantHue SeedHue
|
|
{
|
|
get => Pollinated ? _seedHue : Plant.PlantHue;
|
|
set
|
|
{
|
|
_seedHue = value;
|
|
MarkDirty();
|
|
}
|
|
}
|
|
|
|
private bool ShouldSerializeSeedHue() => _pollinated;
|
|
|
|
[SerializableProperty(16)]
|
|
[SaveFlag(nameof(ShouldSerializeAvailableSeeds))]
|
|
public int AvailableSeeds
|
|
{
|
|
get => _availableSeeds;
|
|
set => _availableSeeds = Math.Max(value, 0);
|
|
}
|
|
|
|
private bool ShouldSerializeAvailableSeeds() => _availableSeeds != 0;
|
|
|
|
[SerializableProperty(17)]
|
|
[SaveFlag(nameof(ShouldSerializeLeftSeeds), nameof(LeftSeedsDefaultValue))]
|
|
public int LeftSeeds
|
|
{
|
|
get => _leftSeeds;
|
|
set => _leftSeeds = Math.Max(value, 0);
|
|
}
|
|
|
|
private bool ShouldSerializeLeftSeeds() => _leftSeeds != 8;
|
|
|
|
private int LeftSeedsDefaultValue() => 8;
|
|
|
|
[SerializableProperty(18)]
|
|
[SaveFlag(nameof(ShouldSerializeAvailableResources))]
|
|
public int AvailableResources
|
|
{
|
|
get => _availableResources;
|
|
set => _availableResources = Math.Max(value, 0);
|
|
}
|
|
|
|
private bool ShouldSerializeAvailableResources() => _availableResources != 0;
|
|
|
|
[SerializableProperty(19)]
|
|
[SaveFlag(nameof(ShouldSerializeLeftResources), nameof(LeftResourcesDefaultValue))]
|
|
public int LeftResources
|
|
{
|
|
get => _leftResources;
|
|
set => _leftResources = Math.Max(value, 0);
|
|
}
|
|
|
|
private bool ShouldSerializeLeftResources() => _leftResources != 8;
|
|
|
|
private int LeftResourcesDefaultValue() => 8;
|
|
|
|
public void Reset(bool potions)
|
|
{
|
|
NextGrowth = Core.Now + CheckDelay;
|
|
GrowthIndicator = PlantGrowthIndicator.None;
|
|
|
|
Hits = MaxHits;
|
|
Infestation = 0;
|
|
Fungus = 0;
|
|
Poison = 0;
|
|
Disease = 0;
|
|
|
|
if (potions)
|
|
{
|
|
PoisonPotion = 0;
|
|
CurePotion = 0;
|
|
HealPotion = 0;
|
|
StrengthPotion = 0;
|
|
}
|
|
|
|
Pollinated = false;
|
|
AvailableSeeds = 0;
|
|
LeftSeeds = 8;
|
|
|
|
AvailableResources = 0;
|
|
LeftResources = 8;
|
|
}
|
|
|
|
public void OnAfterDuped(Item newItem)
|
|
{
|
|
if (newItem is not PlantItem plant)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Copy all properties from this.PlantSystem to plantItem.PlantSystem
|
|
var plantSystem = plant.PlantSystem;
|
|
plantSystem.Water = Water;
|
|
plantSystem.Hits = Hits;
|
|
plantSystem.Infestation = Infestation;
|
|
plantSystem.Fungus = Fungus;
|
|
plantSystem.PoisonPotion = PoisonPotion;
|
|
plantSystem.Disease = Disease;
|
|
plantSystem.PoisonPotion = PoisonPotion;
|
|
plantSystem.CurePotion = CurePotion;
|
|
plantSystem.HealPotion = HealPotion;
|
|
plantSystem.StrengthPotion = StrengthPotion;
|
|
|
|
plantSystem.Pollinated = Pollinated;
|
|
|
|
// Do not use getter since it has computed logic
|
|
plantSystem.SeedType = _seedType;
|
|
plantSystem.SeedHue = _seedHue;
|
|
|
|
plantSystem.AvailableSeeds = AvailableSeeds;
|
|
plantSystem.LeftSeeds = LeftSeeds;
|
|
plantSystem.AvailableResources = AvailableResources;
|
|
plantSystem.LeftResources = LeftResources;
|
|
plantSystem.FertileDirt = FertileDirt;
|
|
plantSystem.NextGrowth = NextGrowth;
|
|
plantSystem.GrowthIndicator = GrowthIndicator;
|
|
}
|
|
|
|
public int GetLocalizedDirtStatus() =>
|
|
Water switch
|
|
{
|
|
<= 1 => 1060826, // hard
|
|
<= 2 => 1060827, // soft
|
|
<= 3 => 1060828, // squishy
|
|
_ => 1060829 // sappy wet
|
|
};
|
|
|
|
public int GetLocalizedHealth()
|
|
{
|
|
return Health switch
|
|
{
|
|
PlantHealth.Dying => 1060825, // dying
|
|
PlantHealth.Wilted => 1060824, // wilted
|
|
PlantHealth.Healthy => 1060823, // healthy
|
|
_ => 1060822 // vibrant
|
|
};
|
|
}
|
|
|
|
public static void Configure()
|
|
{
|
|
EventSink.WorldLoad += EventSink_WorldLoad;
|
|
|
|
if (!AutoRestart.Enabled)
|
|
{
|
|
EventSink.WorldSave += EventSink_WorldSave;
|
|
}
|
|
}
|
|
|
|
[OnEvent(nameof(PlayerMobile.PlayerLoginEvent))]
|
|
public static void OnLogin(PlayerMobile from)
|
|
{
|
|
var cont = from.Backpack;
|
|
if (cont != null)
|
|
{
|
|
foreach (var plant in cont.FindItemsByType<PlantItem>())
|
|
{
|
|
if (plant.IsGrowable)
|
|
{
|
|
plant.PlantSystem.DoGrowthCheck();
|
|
}
|
|
}
|
|
}
|
|
|
|
cont = from.FindBankNoCreate();
|
|
if (cont != null)
|
|
{
|
|
foreach (var plant in cont.FindItemsByType<PlantItem>())
|
|
{
|
|
if (plant.IsGrowable)
|
|
{
|
|
plant.PlantSystem.DoGrowthCheck();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void GrowAll()
|
|
{
|
|
var plants = PlantItem.Plants;
|
|
var now = Core.Now;
|
|
|
|
for (var i = plants.Count - 1; i >= 0; --i)
|
|
{
|
|
var plant = plants[i];
|
|
|
|
if (plant.IsGrowable && plant.RootParent is not Mobile && now >= plant.PlantSystem.NextGrowth)
|
|
{
|
|
plant.PlantSystem.DoGrowthCheck();
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void EventSink_WorldLoad()
|
|
{
|
|
GrowAll();
|
|
}
|
|
|
|
private static void EventSink_WorldSave()
|
|
{
|
|
GrowAll();
|
|
}
|
|
|
|
public void DoGrowthCheck()
|
|
{
|
|
if (!Plant.IsGrowable)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var now = Core.Now;
|
|
|
|
if (now < NextGrowth)
|
|
{
|
|
GrowthIndicator = PlantGrowthIndicator.Delay;
|
|
return;
|
|
}
|
|
|
|
NextGrowth = now + CheckDelay;
|
|
|
|
if (!Plant.ValidGrowthLocation)
|
|
{
|
|
GrowthIndicator = PlantGrowthIndicator.InvalidLocation;
|
|
return;
|
|
}
|
|
|
|
if (Plant.PlantStatus == PlantStatus.BowlOfDirt)
|
|
{
|
|
if (Water > 2 || Utility.RandomDouble() < 0.9)
|
|
{
|
|
Water--;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
ApplyBeneficialEffects();
|
|
|
|
if (!ApplyMaladiesEffects()) // Dead
|
|
{
|
|
return;
|
|
}
|
|
|
|
Grow();
|
|
|
|
UpdateMaladies();
|
|
}
|
|
|
|
private void ApplyBeneficialEffects()
|
|
{
|
|
if (PoisonPotion >= Infestation)
|
|
{
|
|
PoisonPotion -= Infestation;
|
|
Infestation = 0;
|
|
}
|
|
else
|
|
{
|
|
Infestation -= PoisonPotion;
|
|
PoisonPotion = 0;
|
|
}
|
|
|
|
if (CurePotion >= Fungus)
|
|
{
|
|
CurePotion -= Fungus;
|
|
Fungus = 0;
|
|
}
|
|
else
|
|
{
|
|
Fungus -= CurePotion;
|
|
CurePotion = 0;
|
|
}
|
|
|
|
if (HealPotion >= Poison)
|
|
{
|
|
HealPotion -= Poison;
|
|
Poison = 0;
|
|
}
|
|
else
|
|
{
|
|
Poison -= HealPotion;
|
|
HealPotion = 0;
|
|
}
|
|
|
|
if (HealPotion >= Disease)
|
|
{
|
|
HealPotion -= Disease;
|
|
Disease = 0;
|
|
}
|
|
else
|
|
{
|
|
Disease -= HealPotion;
|
|
HealPotion = 0;
|
|
}
|
|
|
|
if (!HasMaladies)
|
|
{
|
|
if (HealPotion > 0)
|
|
{
|
|
Hits += HealPotion * 7;
|
|
}
|
|
else
|
|
{
|
|
Hits += 2;
|
|
}
|
|
}
|
|
|
|
HealPotion = 0;
|
|
}
|
|
|
|
private bool ApplyMaladiesEffects()
|
|
{
|
|
var damage = 0;
|
|
|
|
if (Infestation > 0)
|
|
{
|
|
damage += Infestation * Utility.RandomMinMax(3, 6);
|
|
}
|
|
|
|
if (Fungus > 0)
|
|
{
|
|
damage += Fungus * Utility.RandomMinMax(3, 6);
|
|
}
|
|
|
|
if (Poison > 0)
|
|
{
|
|
damage += Poison * Utility.RandomMinMax(3, 6);
|
|
}
|
|
|
|
if (Disease > 0)
|
|
{
|
|
damage += Disease * Utility.RandomMinMax(3, 6);
|
|
}
|
|
|
|
if (Water > 2)
|
|
{
|
|
damage += (Water - 2) * Utility.RandomMinMax(3, 6);
|
|
}
|
|
else if (Water < 2)
|
|
{
|
|
damage += (2 - Water) * Utility.RandomMinMax(3, 6);
|
|
}
|
|
|
|
Hits -= damage;
|
|
|
|
return Plant.IsGrowable && Plant.PlantStatus != PlantStatus.BowlOfDirt;
|
|
}
|
|
|
|
private void Grow()
|
|
{
|
|
if (Health < PlantHealth.Healthy)
|
|
{
|
|
GrowthIndicator = PlantGrowthIndicator.NotHealthy;
|
|
}
|
|
else if (FertileDirt && Plant.PlantStatus <= PlantStatus.Stage5 && Utility.RandomDouble() < 0.1)
|
|
{
|
|
var curStage = (int)Plant.PlantStatus;
|
|
Plant.PlantStatus = (PlantStatus)(curStage + 2);
|
|
|
|
GrowthIndicator = PlantGrowthIndicator.DoubleGrown;
|
|
}
|
|
else if (Plant.PlantStatus < PlantStatus.Stage9)
|
|
{
|
|
var curStage = (int)Plant.PlantStatus;
|
|
Plant.PlantStatus = (PlantStatus)(curStage + 1);
|
|
|
|
GrowthIndicator = PlantGrowthIndicator.Grown;
|
|
}
|
|
else
|
|
{
|
|
if (Pollinated && LeftSeeds > 0 && Plant.Reproduces)
|
|
{
|
|
LeftSeeds--;
|
|
AvailableSeeds++;
|
|
}
|
|
|
|
if (LeftResources > 0 && PlantResourceInfo.GetInfo(Plant.PlantType, Plant.PlantHue) != null)
|
|
{
|
|
LeftResources--;
|
|
AvailableResources++;
|
|
}
|
|
|
|
GrowthIndicator = PlantGrowthIndicator.Grown;
|
|
}
|
|
|
|
if (Plant.PlantStatus >= PlantStatus.Stage9 && !Pollinated)
|
|
{
|
|
Pollinated = true;
|
|
SeedType = Plant.PlantType;
|
|
SeedHue = Plant.PlantHue;
|
|
}
|
|
}
|
|
|
|
private void UpdateMaladies()
|
|
{
|
|
var infestationChance = 0.30 - StrengthPotion * 0.075 + (Water - 2) * 0.10;
|
|
|
|
var typeInfo = PlantTypeInfo.GetInfo(Plant.PlantType);
|
|
if (typeInfo.Flowery)
|
|
{
|
|
infestationChance += 0.10;
|
|
}
|
|
|
|
if (PlantHueInfo.IsBright(Plant.PlantHue))
|
|
{
|
|
infestationChance += 0.10;
|
|
}
|
|
|
|
if (Utility.RandomDouble() < infestationChance)
|
|
{
|
|
Infestation++;
|
|
}
|
|
|
|
var fungusChance = 0.15 - StrengthPotion * 0.075 + (Water - 2) * 0.10;
|
|
|
|
if (Utility.RandomDouble() < fungusChance)
|
|
{
|
|
Fungus++;
|
|
}
|
|
|
|
if (Water > 2 || Utility.RandomDouble() < 0.9)
|
|
{
|
|
Water--;
|
|
}
|
|
|
|
if (PoisonPotion > 0)
|
|
{
|
|
Poison += PoisonPotion;
|
|
PoisonPotion = 0;
|
|
}
|
|
|
|
if (CurePotion > 0)
|
|
{
|
|
Disease += CurePotion;
|
|
CurePotion = 0;
|
|
}
|
|
|
|
StrengthPotion = 0;
|
|
}
|
|
}
|
|
}
|