From 69290b8c0749c3989fef43bc426d60aa6f0e4422 Mon Sep 17 00:00:00 2001 From: WarrentyExpired Date: Tue, 11 Aug 2026 14:12:58 -0400 Subject: [PATCH] #W# Spawing the Oceans. --- Data/Spawns/overworld.map | 5 + .../Spawner/DynamicSpawner/SpawnRef.cs | 123 ++++++++++++------ 2 files changed, 87 insertions(+), 41 deletions(-) diff --git a/Data/Spawns/overworld.map b/Data/Spawns/overworld.map index 4e67cf9..931d711 100644 --- a/Data/Spawns/overworld.map +++ b/Data/Spawns/overworld.map @@ -1,3 +1,7 @@ +## Ocean +*|seaserpent:deepseaserpent:kraken:leviathan:waterelemental:dolphin||||||1170|1000|-5|1|5|10|-1|1000|1|150|0|0|0|0|0 +*|dolphin||||||933|503|-5|1|5|10|-1|30|1|3|0|0|0|0|0 +## Land *|spawnbirds|spawncritters|spawnanimals|spawn_a|spawn_b|spawn_c|530|160|0|1|5|10|-1|100|1|50|30|30|10|0|0 *|spawnbirds|spawncritters|spawnanimals|spawn_a|spawn_b|spawn_c|530|610|0|1|5|10|-1|100|1|50|30|30|15|0|0 *|spawnbirds|spawncritters|spawnanimals|spawn_a|spawn_b|spawn_c|530|460|0|1|5|10|-1|100|1|50|30|30|15|0|0 @@ -49,3 +53,4 @@ *|spawnbirds|spawnanimals|spawncritters|spawn_a|spawn_d||988|1674|3|1|5|10|-1|30|1|5|5|5|5|2|0 *|spawnbirds|spawnanimals|spawncritters|spawn_a|spawn_d||997|1711|3|1|5|10|-1|30|1|5|5|5|5|2|0 *|spawnbirds|spawncritters|spawnanimals|AncientWyrm|||931|1744|2|1|5|10|-1|20|1|3|3|3|1|0|0 + diff --git a/Scripts/Engines/Spawner/DynamicSpawner/SpawnRef.cs b/Scripts/Engines/Spawner/DynamicSpawner/SpawnRef.cs index 9958ee4..9874c01 100644 --- a/Scripts/Engines/Spawner/DynamicSpawner/SpawnRef.cs +++ b/Scripts/Engines/Spawner/DynamicSpawner/SpawnRef.cs @@ -6,21 +6,15 @@ namespace Server.Items public abstract class BaseSpawner : Item, ISpawner { private Mobile m_TrackedMobile; - - // --- ISpawner Interface Requirements --- - // If true, taming the animal unlinks it and instantly spawns a new wild one! public bool UnlinkOnTaming { get { return true; } } public Point3D HomeLocation { get { return this.Location; } } public int HomeRange { get { return 5; } } - // The Magic Native Event Trigger - // The server calls this natively the instant the creature dies or is deleted. public void Remove( ISpawnable spawn ) { if ( !this.Deleted ) - this.Delete(); // Deleting the proxy item triggers your PremiumSpawner to respawn! + this.Delete(); } - // --------------------------------------- public BaseSpawner() : base( 0x6519 ) { @@ -38,7 +32,7 @@ namespace Server.Items public override void Serialize( GenericWriter writer ) { base.Serialize( writer ); - writer.Write( (int) 0 ); // version + writer.Write( (int) 0 ); writer.Write( m_TrackedMobile ); } @@ -49,7 +43,6 @@ namespace Server.Items int version = reader.ReadInt(); m_TrackedMobile = reader.ReadMobile(); - // Re-link the spawner if the server restarts and the mob is still alive if ( m_TrackedMobile != null && !m_TrackedMobile.Deleted && m_TrackedMobile.Alive ) { if ( m_TrackedMobile is ISpawnable ) @@ -64,44 +57,92 @@ namespace Server.Items } private void ExecuteSpawn() - { - if ( !this.Deleted && this.Map != null && this.Map != Map.Internal ) - { - Point3D savedLocation = this.Location; - Map savedMap = this.Map; - Region reg = Region.Find( savedLocation, savedMap ); - if ( reg is Server.Regions.TownRegion || - reg is Server.Regions.GuardedRegion ) + { + if ( !this.Deleted && this.Map != null && this.Map != Map.Internal ) + { + Point3D savedLocation = this.Location; + Map savedMap = this.Map; + + // --- REGION SAFETY CHECK --- + Region reg = Region.Find( savedLocation, savedMap ); + if ( reg is Server.Regions.TownRegion || + reg is Server.Regions.GuardedRegion || + reg is Server.Regions.HouseRegion ) { this.Delete(); return; } - m_TrackedMobile = Server.SpawnList.RandomSpawn( this, savedLocation, savedMap ); - - if ( m_TrackedMobile != null ) - { - // Link the newly born mobile to this proxy item! - if ( m_TrackedMobile is ISpawnable ) - { - ((ISpawnable)m_TrackedMobile).Spawner = this; - } + // --------------------------- - m_TrackedMobile.MoveToWorld( savedLocation, savedMap ); - - this.Internalize(); - } - else - { - this.Delete(); - } - } - else if ( !this.Deleted ) - { - this.Delete(); - } - } + m_TrackedMobile = Server.SpawnList.RandomSpawn( this, savedLocation, savedMap ); + + if ( m_TrackedMobile != null ) + { + if ( m_TrackedMobile is ISpawnable ) + { + ((ISpawnable)m_TrackedMobile).Spawner = this; + } + + // --- NEW SCATTER LOGIC --- + int scatterRange = 25; // Default fallback range + + // 1. Look down at our feet to find the parent spawner and borrow its HomeRange! + foreach ( Item item in savedMap.GetItemsInRange( savedLocation, 0 ) ) + { + if ( item is ISpawner ) + { + scatterRange = ((ISpawner)item).HomeRange; + break; + } + } + + Point3D spawnPoint = savedLocation; + + // 2. Try up to 15 times to find a valid tile within that range + for ( int i = 0; i < 15; i++ ) + { + int x = savedLocation.X + Utility.RandomMinMax( -scatterRange, scatterRange ); + int y = savedLocation.Y + Utility.RandomMinMax( -scatterRange, scatterRange ); + int z = savedMap.GetAverageZ( x, y ); + Point3D testPoint = new Point3D( x, y, z ); + + // If this is the water proxy, specifically seek out water tiles using your SpawnList system + if ( this is SpawnWater ) + { + if ( Server.SpawnList.GetTerrain( savedMap, testPoint, x, y ) == Server.Terrain.Water ) + { + spawnPoint = testPoint; + break; // Found a valid water spot! + } + } + // If it's a land proxy, ensure the mob doesn't accidentally spawn in the ocean + else + { + if ( savedMap.CanFit( x, y, z, 16, false, false ) ) + { + spawnPoint = testPoint; + break; // Found a valid land spot! + } + } + } + // ------------------------- + + // Move the mob to the scattered location instead of the center + m_TrackedMobile.MoveToWorld( spawnPoint, savedMap ); + + this.Internalize(); + } + else + { + this.Delete(); + } + } + else if ( !this.Deleted ) + { + this.Delete(); + } + } } - public class SpawnAnimals : BaseSpawner { [Constructable]