using System; using System.Collections; using Server; using Server.Items; using System.Collections.Generic; namespace Server.Engines.Plants { public enum PlantHealth { Dying, Wilted, Healthy, Vibrant } public enum PlantGrowthIndicator { None, InvalidLocation, NotHealthy, Delay, Grown, DoubleGrown } public class PlantSystem { public static readonly TimeSpan CheckDelay = TimeSpan.FromHours( 23.0 ); private int m_Water; private int m_Hits; private int m_Infestation; private int m_Fungus; private int m_Poison; private int m_Disease; private int m_PoisonPotion; private int m_CurePotion; private int m_HealPotion; private int m_StrengthPotion; private PlantType m_SeedType; private PlantHue m_SeedHue; private int m_AvailableSeeds; private int m_LeftSeeds; private int m_AvailableResources; private int m_LeftResources; public PlantItem Plant { get; } public bool FertileDirt { get; set; } public DateTime NextGrowth { get; set; } public PlantGrowthIndicator GrowthIndicator { get; private set; } public bool IsFullWater { get { return m_Water >= 4; } } public int Water { get { return m_Water; } set { if ( value < 0 ) m_Water = 0; else if ( value > 4 ) m_Water = 4; else m_Water = value; Plant.InvalidateProperties(); } } public int Hits { get { return m_Hits; } set { if ( m_Hits == value ) return; if ( value < 0 ) m_Hits = 0; else if ( value > MaxHits ) m_Hits = MaxHits; else m_Hits = value; if ( m_Hits == 0 ) Plant.Die(); Plant.InvalidateProperties(); } } public int MaxHits { get { return 10 + (int)Plant.PlantStatus * 2; } } public PlantHealth Health { get { int perc = m_Hits * 100 / MaxHits; if ( perc < 33 ) return PlantHealth.Dying; else if ( perc < 66 ) return PlantHealth.Wilted; else if ( perc < 100 ) return PlantHealth.Healthy; else return PlantHealth.Vibrant; } } public int Infestation { get { return m_Infestation; } set { if ( value < 0 ) m_Infestation = 0; else if ( value > 2 ) m_Infestation = 2; else m_Infestation = value; } } public int Fungus { get { return m_Fungus; } set { if ( value < 0 ) m_Fungus = 0; else if ( value > 2 ) m_Fungus = 2; else m_Fungus = value; } } public int Poison { get { return m_Poison; } set { if ( value < 0 ) m_Poison = 0; else if ( value > 2 ) m_Poison = 2; else m_Poison = value; } } public int Disease { get { return m_Disease; } set { if ( value < 0 ) m_Disease = 0; else if ( value > 2 ) m_Disease = 2; else m_Disease = value; } } public bool IsFullPoisonPotion { get { return m_PoisonPotion >= 2; } } public int PoisonPotion { get { return m_PoisonPotion; } set { if ( value < 0 ) m_PoisonPotion = 0; else if ( value > 2 ) m_PoisonPotion = 2; else m_PoisonPotion = value; } } public bool IsFullCurePotion { get { return m_CurePotion >= 2; } } public int CurePotion { get { return m_CurePotion; } set { if ( value < 0 ) m_CurePotion = 0; else if ( value > 2 ) m_CurePotion = 2; else m_CurePotion = value; } } public bool IsFullHealPotion { get { return m_HealPotion >= 2; } } public int HealPotion { get { return m_HealPotion; } set { if ( value < 0 ) m_HealPotion = 0; else if ( value > 2 ) m_HealPotion = 2; else m_HealPotion = value; } } public bool IsFullStrengthPotion { get { return m_StrengthPotion >= 2; } } public int StrengthPotion { get { return m_StrengthPotion; } set { if ( value < 0 ) m_StrengthPotion = 0; else if ( value > 2 ) m_StrengthPotion = 2; else m_StrengthPotion = value; } } public bool HasMaladies { get { return Infestation > 0 || Fungus > 0 || Poison > 0 || Disease > 0 || Water != 2; } } public bool PollenProducing { get { return Plant.IsCrossable && Plant.PlantStatus >= PlantStatus.FullGrownPlant; } } public bool Pollinated { get; set; } public PlantType SeedType { get { if ( Pollinated ) return m_SeedType; else return Plant.PlantType; } set { m_SeedType = value; } } public PlantHue SeedHue { get { if ( Pollinated ) return m_SeedHue; else return Plant.PlantHue; } set { m_SeedHue = value; } } public int AvailableSeeds { get { return m_AvailableSeeds; } set { if ( value >= 0 ) m_AvailableSeeds = value; } } public int LeftSeeds { get { return m_LeftSeeds; } set { if ( value >= 0 ) m_LeftSeeds = value; } } public int AvailableResources { get { return m_AvailableResources; } set { if ( value >= 0 ) m_AvailableResources = value; } } public int LeftResources { get { return m_LeftResources; } set { if ( value >= 0 ) m_LeftResources = value; } } public PlantSystem( PlantItem plant, bool fertileDirt ) { Plant = plant; FertileDirt = fertileDirt; NextGrowth = DateTime.UtcNow + CheckDelay; GrowthIndicator = PlantGrowthIndicator.None; m_Hits = MaxHits; m_LeftSeeds = 8; m_LeftResources = 8; } public void Reset( bool potions ) { NextGrowth = DateTime.UtcNow + CheckDelay; GrowthIndicator = PlantGrowthIndicator.None; Hits = MaxHits; m_Infestation = 0; m_Fungus = 0; m_Poison = 0; m_Disease = 0; if ( potions ) { m_PoisonPotion = 0; m_CurePotion = 0; m_HealPotion = 0; m_StrengthPotion = 0; } Pollinated = false; m_AvailableSeeds = 0; m_LeftSeeds = 8; m_AvailableResources = 0; m_LeftResources = 8; } public int GetLocalizedDirtStatus() { if(!Plant.RequiresUpkeep) return 1060827; // soft if ( Water <= 1 ) return 1060826; // hard else if ( Water <= 2 ) return 1060827; // soft else if ( Water <= 3 ) return 1060828; // squishy else return 1060829; // sopping wet } public int GetLocalizedHealth() { switch ( Health ) { case PlantHealth.Dying: return 1060825; // dying case PlantHealth.Wilted: return 1060824; // wilted case PlantHealth.Healthy: return 1060823; // healthy default: return 1060822; // vibrant } } public static void Configure() { EventSink.WorldLoad += new WorldLoadEventHandler( EventSink_WorldLoad ); if ( !Misc.AutoRestart.Enabled ) EventSink.WorldSave += new WorldSaveEventHandler( EventSink_WorldSave ); EventSink.Login += new LoginEventHandler( EventSink_Login ); } private static void EventSink_Login( LoginEventArgs args ) { Mobile from = args.Mobile; if ( from.Backpack != null ) { List plants = from.Backpack.FindItemsByType(); foreach ( PlantItem plant in plants ) { if ( plant.IsGrowable ) plant.PlantSystem.DoGrowthCheck(); } } BankBox bank = from.FindBankNoCreate(); if ( bank != null ) { List plants = bank.FindItemsByType(); foreach ( PlantItem plant in plants ) { if ( plant.IsGrowable ) plant.PlantSystem.DoGrowthCheck(); } } } public static void GrowAll() { ArrayList plants = PlantItem.Plants; DateTime now = DateTime.UtcNow; for ( int i = plants.Count - 1; i >= 0; --i ) { PlantItem plant = (PlantItem) plants[i]; if ( plant.IsGrowable && (plant.RootParent as Mobile) == null && now >= plant.PlantSystem.NextGrowth ) plant.PlantSystem.DoGrowthCheck(); } } private static void EventSink_WorldLoad() { GrowAll(); } private static void EventSink_WorldSave( WorldSaveEventArgs args) { GrowAll(); } public bool MaginciaPlantContract => Plant.MaginciaPlant && ((MaginciaPlantItem)Plant).IsContract; public void DoGrowthCheck() { if (!Plant.IsGrowable) return; if ( DateTime.UtcNow < NextGrowth ) { GrowthIndicator = PlantGrowthIndicator.Delay; return; } NextGrowth = DateTime.UtcNow + CheckDelay; if (!Plant.ValidGrowthLocation) { GrowthIndicator = PlantGrowthIndicator.InvalidLocation; return; } if (!MaginciaPlantContract) { if (Plant.PlantStatus == PlantStatus.BowlOfDirt) { if (Water > 2 || Utility.RandomDouble() < 0.9) Water--; return; } ApplyBeneficEffects(); if (!ApplyMaladiesEffects()) // Dead return; } Grow(); if (!MaginciaPlantContract) UpdateMaladies(); } private void ApplyBeneficEffects() { 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() { if ( !Plant.RequiresUpkeep ) return true; int 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 ) { int curStage = (int)Plant.PlantStatus; Plant.PlantStatus = (PlantStatus)( curStage + 2 ); GrowthIndicator = PlantGrowthIndicator.DoubleGrown; } else if ( Plant.PlantStatus < PlantStatus.Stage9 ) { int curStage = (int)Plant.PlantStatus; Plant.PlantStatus = (PlantStatus)( curStage + 1 ); GrowthIndicator = PlantGrowthIndicator.Grown; } else { if ( Pollinated && LeftSeeds > 0 && Plant.Reproduces ) { LeftSeeds--; AvailableSeeds++; } if ( !Plant.MaginciaPlant && LeftResources > 0 && PlantResourceInfo.GetInfo( Plant.PlantType, Plant.PlantHue ) != null ) { LeftResources--; AvailableResources++; } GrowthIndicator = PlantGrowthIndicator.Grown; } if ( Plant.PlantStatus >= PlantStatus.Stage9 && !Pollinated && !Plant.MaginciaPlant ) { Pollinated = true; SeedType = Plant.PlantType; SeedHue = Plant.PlantHue; } } private void UpdateMaladies() { if ( !Plant.RequiresUpkeep ) return; double infestationChance = 0.30 - StrengthPotion * 0.075 + ( Water - 2 ) * 0.10; PlantTypeInfo typeInfo = PlantTypeInfo.GetInfo( Plant.PlantType ); if ( typeInfo.Flowery ) infestationChance += 0.10; if ( PlantHueInfo.IsBright( Plant.PlantHue ) ) infestationChance += 0.10; if ( Utility.RandomDouble() < infestationChance ) Infestation++; double 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; } public void Save( GenericWriter writer ) { writer.Write( (int) 2 ); // version writer.Write( (bool) FertileDirt ); writer.Write( (DateTime) NextGrowth ); writer.Write( (int) GrowthIndicator ); writer.Write( (int) m_Water ); writer.Write( (int) m_Hits ); writer.Write( (int) m_Infestation ); writer.Write( (int) m_Fungus ); writer.Write( (int) m_Poison ); writer.Write( (int) m_Disease ); writer.Write( (int) m_PoisonPotion ); writer.Write( (int) m_CurePotion ); writer.Write( (int) m_HealPotion ); writer.Write( (int) m_StrengthPotion ); writer.Write( (bool) Pollinated ); writer.Write( (int) m_SeedType ); writer.Write( (int) m_SeedHue ); writer.Write( (int) m_AvailableSeeds ); writer.Write( (int) m_LeftSeeds ); writer.Write( (int) m_AvailableResources ); writer.Write( (int) m_LeftResources ); } public PlantSystem( PlantItem plant, GenericReader reader ) { Plant = plant; int version = reader.ReadInt(); FertileDirt = reader.ReadBool(); if ( version >= 1 ) NextGrowth = reader.ReadDateTime(); else NextGrowth = reader.ReadDeltaTime(); GrowthIndicator = (PlantGrowthIndicator)reader.ReadInt(); m_Water = reader.ReadInt(); m_Hits = reader.ReadInt(); m_Infestation = reader.ReadInt(); m_Fungus = reader.ReadInt(); m_Poison = reader.ReadInt(); m_Disease = reader.ReadInt(); m_PoisonPotion = reader.ReadInt(); m_CurePotion = reader.ReadInt(); m_HealPotion = reader.ReadInt(); m_StrengthPotion = reader.ReadInt(); Pollinated = reader.ReadBool(); m_SeedType = (PlantType)reader.ReadInt(); m_SeedHue = (PlantHue)reader.ReadInt(); m_AvailableSeeds = reader.ReadInt(); m_LeftSeeds = reader.ReadInt(); m_AvailableResources = reader.ReadInt(); m_LeftResources = reader.ReadInt(); if ( version < 2 && PlantHueInfo.IsCrossable( m_SeedHue ) ) m_SeedHue |= PlantHue.Reproduces; } } }