public Point3D RandomSpawnLocation( int spawnHeight, bool land, bool water, Point3D home, int range )
{
Map map = this.Map;
if ( map == Map.Internal )
return Point3D.Zero;
InitRectangles();
if ( m_TotalWeight <= 0 )
return Point3D.Zero;
for ( int i = 0; i < 10; i++ ) // Try 10 times
{
int x, y, minZ, maxZ;
if ( home == Point3D.Zero )
{
int rand = Utility.Random( m_TotalWeight );
x = int.MinValue; y = int.MinValue;
minZ = int.MaxValue; maxZ = int.MinValue;
for ( int j = 0; j < m_RectangleWeights.Length; j++ )
{
int curWeight = m_RectangleWeights[j];
if ( rand < curWeight )
{
Rectangle3D rect = m_Rectangles[j];
x = rect.Start.X + rand % rect.Width;
y = rect.Start.Y + rand / rect.Width;
minZ = rect.Start.Z;
maxZ = rect.End.Z;
break;
}
rand -= curWeight;
}
}
else
{
x = Utility.RandomMinMax( home.X - range, home.X + range );
y = Utility.RandomMinMax( home.Y - range, home.Y + range );
minZ = int.MaxValue; maxZ = int.MinValue;
for ( int j = 0; j < this.Area.Length; j++ )
{
Rectangle3D rect = this.Area[j];
if ( x >= rect.Start.X && x < rect.End.X && y >= rect.Start.Y && y < rect.End.Y )
{
minZ = rect.Start.Z;
maxZ = rect.End.Z;
break;
}
}
if ( minZ == int.MaxValue )
continue;
}
if ( x < 0 || y < 0 || x >= map.Width || y >= map.Height )
continue;
LandTile lt = map.Tiles.GetLandTile( x, y );
int ltLowZ = 0, ltAvgZ = 0, ltTopZ = 0;
map.GetAverageZ( x, y, ref ltLowZ, ref ltAvgZ, ref ltTopZ );
TileFlag ltFlags = TileData.LandTable[lt.ID & TileData.MaxLandValue].Flags;
bool ltImpassable = ( (ltFlags & TileFlag.Impassable) != 0 );
if ( !lt.Ignored && ltAvgZ >= minZ && ltAvgZ < maxZ )
if ( (ltFlags & TileFlag.Wet) != 0 ) {
if ( water )
m_SpawnBuffer1.Add( ltAvgZ );
}
else if ( land && !ltImpassable )
m_SpawnBuffer1.Add( ltAvgZ );
StaticTile[] staticTiles = map.Tiles.GetStaticTiles( x, y, true );
for ( int j = 0; j < staticTiles.Length; j++ )
{
StaticTile tile = staticTiles[j];
ItemData id = TileData.ItemTable[tile.ID & TileData.MaxItemValue];
int tileZ = tile.Z + id.CalcHeight;
if ( tileZ >= minZ && tileZ < maxZ )
if ( (id.Flags & TileFlag.Wet) != 0 ) {
if ( water )
m_SpawnBuffer1.Add( tileZ );
}
else if ( land && id.Surface && !id.Impassable )
m_SpawnBuffer1.Add( tileZ );
}
Sector sector = map.GetSector( x, y );
for ( int j = 0; j < sector.Items.Count; j++ )
{
Item item = sector.Items[j];
if ( !(item is BaseMulti) && item.ItemID <= TileData.MaxItemValue && item.AtWorldPoint( x, y ) )
{
m_SpawnBuffer2.Add( item );
if ( !item.Movable )
{
ItemData id = item.ItemData;
int itemZ = item.Z + id.CalcHeight;
if ( itemZ >= minZ && itemZ < maxZ )
if ( (id.Flags & TileFlag.Wet) != 0 ) {
if ( water )
m_SpawnBuffer1.Add( itemZ );
}
else if ( land && id.Surface && !id.Impassable )
m_SpawnBuffer1.Add( itemZ );
}
}
}
if ( m_SpawnBuffer1.Count == 0 )
{
m_SpawnBuffer1.Clear();
m_SpawnBuffer2.Clear();
continue;
}
int z;
switch ( m_SpawnZLevel )
{
case SpawnZLevel.Lowest:
{
z = int.MaxValue;
for ( int j = 0; j < m_SpawnBuffer1.Count; j++ )
{
int l = m_SpawnBuffer1[j];
if ( l < z )
z = l;
}
break;
}
case SpawnZLevel.Highest:
{
z = int.MinValue;
for ( int j = 0; j < m_SpawnBuffer1.Count; j++ )
{
int l = m_SpawnBuffer1[j];
if ( l > z )
z = l;
}
break;
}
default: // SpawnZLevel.Random
{
int index = Utility.Random( m_SpawnBuffer1.Count );
z = m_SpawnBuffer1[index];
break;
}
}
m_SpawnBuffer1.Clear();
if ( !Region.Find( new Point3D( x, y, z ), map ).AcceptsSpawnsFrom( this ) )
{
m_SpawnBuffer2.Clear();
continue;
}
int top = z + spawnHeight;
bool ok = true;
for ( int j = 0; j < m_SpawnBuffer2.Count; j++ )
{
Item item = m_SpawnBuffer2[j];
ItemData id = item.ItemData;
if ( ( id.Surface || id.Impassable ) && item.Z + id.CalcHeight > z && item.Z < top )
{
ok = false;
break;
}
}
m_SpawnBuffer2.Clear();
if ( !ok )
continue;
if ( ltImpassable && ltAvgZ > z && ltLowZ < top )
continue;
for ( int j = 0; j < staticTiles.Length; j++ )
{
StaticTile tile = staticTiles[j];
ItemData id = TileData.ItemTable[tile.ID & TileData.MaxItemValue];
if ( ( id.Surface || id.Impassable ) && tile.Z + id.CalcHeight > z && tile.Z < top )
{
ok = false;
break;
}
}
if ( !ok )
continue;
for ( int j = 0; j < sector.Mobiles.Count; j++ )
{
Mobile m = sector.Mobiles[j];
if ( m.X == x && m.Y == y && ( m.AccessLevel == AccessLevel.Player || !m.Hidden ) )
if ( m.Z + 16 > z && m.Z < top )
{
ok = false;
break;
}
}
if ( ok )
return new Point3D( x, y, z );
}
return Point3D.Zero;
}