using System;
using System.Collections;
using Server.Mobiles;
namespace Server
{
public class VendorGenerator
{
public static void Initialize()
{
Commands.Register( "VendorGen", AccessLevel.Administrator, new CommandEventHandler( VendorGenerator.VendorGen_OnCommand ) );
}
private static Rectangle2D[] m_BritRegions = new Rectangle2D[]
{
new Rectangle2D( new Point2D( 250, 750 ), new Point2D( 775, 1330 ) ),
new Rectangle2D( new Point2D( 525, 2095 ), new Point2D( 925, 2430 ) ),
new Rectangle2D( new Point2D( 1025, 2155 ), new Point2D( 1265, 2310 ) ),
new Rectangle2D( new Point2D( 1635, 2430 ), new Point2D( 1705, 2508 ) ),
new Rectangle2D( new Point2D( 1775, 2605 ), new Point2D( 2165, 2975 ) ),
new Rectangle2D( new Point2D( 1055, 3520 ), new Point2D( 1570, 4075 ) ),
new Rectangle2D( new Point2D( 2860, 3310 ), new Point2D( 3120, 3630 ) ),
new Rectangle2D( new Point2D( 2470, 1855 ), new Point2D( 3950, 3045 ) ),
new Rectangle2D( new Point2D( 3425, 990 ), new Point2D( 3900, 1455 ) ),
new Rectangle2D( new Point2D( 4175, 735 ), new Point2D( 4840, 1600 ) ),
new Rectangle2D( new Point2D( 2375, 330 ), new Point2D( 3100, 1045 ) ),
new Rectangle2D( new Point2D( 2100, 1090 ), new Point2D( 2310, 1450 ) ),
new Rectangle2D( new Point2D( 1495, 1400 ), new Point2D( 1550, 1475 ) ),
new Rectangle2D( new Point2D( 1085, 1520 ), new Point2D( 1415, 1910 ) ),
new Rectangle2D( new Point2D( 1410, 1500 ), new Point2D( 1745, 1795 ) ),
new Rectangle2D( new Point2D( 5120, 2300 ), new Point2D( 6143, 4095 ) )
};
private static Rectangle2D[] m_IlshRegions = new Rectangle2D[]
{
new Rectangle2D( new Point2D( 0, 0 ), new Point2D( 288*8, 200*8 ) )
};
[Usage( "VendorGen" )]
[Description( "Generates vendors based on display cases and floor plans. Analyzes the map files, slow." )]
private static void VendorGen_OnCommand( CommandEventArgs e )
{
Process( Map.Trammel, m_BritRegions );
Process( Map.Felucca, m_BritRegions );
Process( Map.Ilshenar, m_IlshRegions );
}
private static bool GetFloorZ( Map map, int x, int y, out int z )
{
Tile lt = map.Tiles.GetLandTile( x, y );
if ( IsFloor( lt.ID ) && map.CanFit( x, y, lt.Z, 16, false, false ) )
{
z = lt.Z;
return true;
}
Tile[] tiles = map.Tiles.GetStaticTiles( x, y );
for ( int i = 0; i < tiles.Length; ++i )
{
Tile t = tiles[i];
ItemData id = TileData.ItemTable[t.ID & 0x3FFF];
if ( IsStaticFloor( t.ID ) && map.CanFit( x, y, t.Z + (id.Surface ? id.CalcHeight : 0), 16, false, false ) )
{
z = t.Z + (id.Surface ? id.CalcHeight : 0);
return true;
}
}
z = 0;
return false;
}
private static bool IsFloor( Map map, int x, int y, bool canFit )
{
Tile lt = map.Tiles.GetLandTile( x, y );
if ( IsFloor( lt.ID ) && (canFit||CanFit( map, x, y, lt.Z )) )
return true;
Tile[] tiles = map.Tiles.GetStaticTiles( x, y );
for ( int i = 0; i < tiles.Length; ++i )
{
Tile t = tiles[i];
ItemData id = TileData.ItemTable[t.ID & 0x3FFF];
if ( IsStaticFloor( t.ID ) && (canFit||CanFit( map, x, y, t.Z + (id.Surface ? id.CalcHeight : 0) )) )
return true;
}
return false;
}
private static bool IsFloor( int itemID )
{
itemID &= 0x3FFF;
return ( itemID >= 0x406 && itemID <= 0x51A );
}
private static bool IsStaticFloor( int itemID )
{
itemID &= 0x3FFF;
return ( itemID >= 0x495 && itemID <= 0x514 )
|| ( itemID >= 0x519 && itemID <= 0x53A );
}
private static bool IsDisplayCase( int itemID )
{
itemID &= 0x3FFF;
return ( itemID >= 0xB00 && itemID <= 0xB02 )
|| ( itemID >= 0xB06 && itemID <= 0xB0A )
|| ( itemID >= 0xB0D && itemID <= 0xB17 );
}
private static void Process( Map map, Rectangle2D[] regions )
{
m_ShopTable = new Hashtable();
m_ShopList = new ArrayList();
World.Broadcast( 0x35, true, "Generating vendor spawns for {0}, please wait.", map );
for ( int i = 0; i < regions.Length; ++i )
for ( int x = 0; x < map.Width; ++x )
for ( int y = 0; y < map.Height; ++y )
CheckPoint( map, regions[i].X + x, regions[i].Y + y );
for ( int i = 0; i < m_ShopList.Count; ++i )
{
ShopInfo si = (ShopInfo)m_ShopList[i];
int xTotal = 0;
int yTotal = 0;
bool hasSpawner = false;
for ( int j = 0; !hasSpawner && j < si.m_Floor.Count; ++j )
{
Point2D fp = (Point2D)si.m_Floor[j];
xTotal += fp.X;
yTotal += fp.Y;
IPooledEnumerable eable = map.GetItemsInRange( new Point3D( fp.X, fp.Y, 0 ), 0 );
foreach ( Item item in eable )
{
if ( item is Spawner )
{
hasSpawner = true;
break;
}
}
eable.Free();
if ( hasSpawner )
break;
}
if ( hasSpawner )
continue;
int xAvg = xTotal / si.m_Floor.Count;
int yAvg = yTotal / si.m_Floor.Count;
ArrayList names = new ArrayList();
ShopFlags flags = si.m_Flags;
if ( (flags & ShopFlags.Armor) != 0 )
names.Add( "armorer" );
if ( (flags & ShopFlags.MetalWeapon) != 0 )
names.Add( "weaponsmith" );
if ( (flags & ShopFlags.ArcheryWeapon) != 0 )
names.Add( "bowyer" );
if ( (flags & ShopFlags.Scroll) != 0 )
names.Add( "mage" );
if ( (flags & ShopFlags.Spellbook) != 0 )
names.Add( "mage" );
if ( (flags & ShopFlags.Bread) != 0 )
names.Add( "baker" );
if ( (flags & ShopFlags.Jewel) != 0 )
names.Add( "jeweler" );
if ( (flags & ShopFlags.Potion) != 0 )
{
names.Add( "herbalist" );
names.Add( "alchemist" );
names.Add( "mage" );
}
if ( (flags & ShopFlags.Reagent) != 0 )
{
names.Add( "mage" );
names.Add( "herbalist" );
}
if ( (flags & ShopFlags.Clothes) != 0 )
{
names.Add( "tailor" );
names.Add( "weaver" );
}
for ( int j = 0; j < names.Count; ++j )
{
Point2D cp = Point2D.Zero;
int dist = 100000;
int tz;
for ( int k = 0; k < si.m_Floor.Count; ++k )
{
Point2D fp = (Point2D)si.m_Floor[k];
int rx = fp.X - xAvg;
int ry = fp.Y - yAvg;
int fd = (int)Math.Sqrt( rx*rx + ry*ry );
if ( fd > 0 && fd < 5 )
fd -= Utility.Random( 10 );
if ( fd < dist && GetFloorZ( map, fp.X, fp.Y, out tz ) )
{
dist = fd;
cp = fp;
}
}
if ( cp == Point2D.Zero )
continue;
int z;
if ( !GetFloorZ( map, cp.X, cp.Y, out z ) )
continue;
new Spawner( 1, 1, 1, 0, 4, (string)names[j] ).MoveToWorld( new Point3D( cp.X, cp.Y, z ), map );
}
}
World.Broadcast( 0x35, true, "Generation complete. {0} spawners generated.", m_ShopList.Count );
}
private static void CheckPoint( Map map, int x, int y )
{
if ( IsFloor( map, x, y, true ) )
CheckFloor( map, x, y );
}
private static void CheckFloor( Map map, int x, int y )
{
Tile[] tiles = map.Tiles.GetStaticTiles( x, y );
for ( int i = 0; i < tiles.Length; ++i )
{
if ( IsDisplayCase( tiles[i].ID ) )
{
ProcessDisplayCase( map, tiles, x, y );
break;
}
}
}
[Flags]
private enum ShopFlags
{
None = 0x000,
Armor = 0x001,
MetalWeapon = 0x002,
Jewel = 0x004,
Reagent = 0x008,
Potion = 0x010,
Bread = 0x020,
Clothes = 0x040,
ArcheryWeapon = 0x080,
Scroll = 0x100,
Spellbook = 0x200
}
private static bool IsClothes( int itemID )
{
if ( itemID >= 0x1515 && itemID <= 0x1518 )
return true;
if ( itemID >= 0x152E && itemID <= 0x1531 )
return true;
if ( itemID >= 0x1537 && itemID <= 0x154C )
return true;
if ( itemID >= 0x1EFD && itemID <= 0x1F04 )
return true;
if ( itemID >= 0x170B && itemID <= 0x171C )
return true;
return false;
}
private static bool IsArmor( int itemID )
{
if ( itemID >= 0x13BB && itemID <= 0x13E2 )
return true;
if ( itemID >= 0x13E5 && itemID <= 0x13F2 )
return true;
if ( itemID >= 0x1408 && itemID <= 0x141A )
return true;
if ( itemID >= 0x144E && itemID <= 0x1457 )
return true;
return false;
}
private static bool IsMetalWeapon( int itemID )
{
if ( itemID >= 0xF43 && itemID <= 0xF4E )
return true;
if ( itemID >= 0xF51 && itemID <= 0xF52 )
return true;
if ( itemID >= 0xF5C && itemID <= 0xF63 )
return true;
if ( itemID >= 0x13AF && itemID <= 0x13B0 )
return true;
if ( itemID >= 0x13B5 && itemID <= 0x13BA )
return true;
if ( itemID >= 0x13FA && itemID <= 0x13FB )
return true;
if ( itemID >= 0x13FE && itemID <= 0x1407 )
return true;
if ( itemID >= 0x1438 && itemID <= 0x1443 )
return true;
return false;
}
private static bool IsArcheryWeapon( int itemID )
{
if ( itemID >= 0xF4F && itemID <= 0xF50 )
return true;
if ( itemID >= 0x13B1 && itemID <= 0x13B2 )
return true;
if ( itemID >= 0x13FC && itemID <= 0x13FD )
return true;
return false;
}
private static ShopFlags ProcessDisplayedItem( int itemID )
{
itemID &= 0x3FFF;
ShopFlags res = ShopFlags.None;
ItemData id = TileData.ItemTable[itemID];
TileFlag flags = id.Flags;
if ( (flags & TileFlag.Wearable) != 0 )
{
if ( IsClothes( itemID ) )
res |= ShopFlags.Clothes;
else if ( IsArmor( itemID ) )
res |= ShopFlags.Armor;
else if ( IsMetalWeapon( itemID ) )
res |= ShopFlags.MetalWeapon;
else if ( IsArcheryWeapon( itemID ) )
res |= ShopFlags.ArcheryWeapon;
}
if ( itemID == 0x98C || itemID == 0x103B || itemID == 0x103C )
res |= ShopFlags.Bread;
if ( itemID >= 0xF0F && itemID <= 0xF30 )
res |= ShopFlags.Jewel;
if ( itemID >= 0xEFB && itemID <= 0xF0D )
res |= ShopFlags.Potion;
if ( itemID >= 0xF78 && itemID <= 0xF91 )
res |= ShopFlags.Reagent;
if ( (itemID >= 0xE35 && itemID <= 0xE3A) || (itemID >= 0xEF4 && itemID <= 0xEF9) || (itemID >= 0x1F2D && itemID <= 0x1F72) )
res |= ShopFlags.Scroll;
if ( itemID == 0xE38 || itemID == 0xEFA )
res |= ShopFlags.Spellbook;
return res;
}
private static void ProcessDisplayCase( Map map, Tile[] tiles, int x, int y )
{
ShopFlags flags = ShopFlags.None;
for ( int i = 0; i < tiles.Length; ++i )
flags |= ProcessDisplayedItem( tiles[i].ID );
if ( flags != ShopFlags.None )
{
Point2D p = new Point2D( x, y );
ShopInfo si = (ShopInfo)m_ShopTable[p];
if ( si == null )
{
ArrayList floor = new ArrayList();
RecurseFindFloor( map, x, y, floor );
if ( floor.Count == 0 )
return;
si = new ShopInfo();
si.m_Flags = flags;
si.m_Floor = floor;
m_ShopList.Add( si );
for ( int i = 0; i < floor.Count; ++i )
m_ShopTable[(Point2D)floor[i]] = si;
}
else
{
si.m_Flags |= flags;
}
}
}
private static Hashtable m_ShopTable;
private static ArrayList m_ShopList;
private class ShopInfo
{
public ShopFlags m_Flags;
public ArrayList m_Floor;
}
private static bool CanFit( Map map, int x, int y, int z )
{
bool hasSurface = false;
Tile lt = map.Tiles.GetLandTile( x, y );
int lowZ = 0, avgZ = 0, topZ = 0;
map.GetAverageZ( x, y, ref lowZ, ref avgZ, ref topZ );
TileFlag landFlags = TileData.LandTable[lt.ID & 0x3FFF].Flags;
if ( (landFlags & TileFlag.Impassable) != 0 && topZ > z && (z + 16) > lowZ )
return false;
else if ( (landFlags & TileFlag.Impassable) == 0 && z == avgZ && !lt.Ignored )
hasSurface = true;
Tile[] staticTiles = map.Tiles.GetStaticTiles( x, y );
bool surface, impassable;
for ( int i = 0; i < staticTiles.Length; ++i )
{
if ( IsDisplayCase( staticTiles[i].ID ) )
continue;
ItemData id = TileData.ItemTable[staticTiles[i].ID & 0x3FFF];
surface = id.Surface;
impassable = id.Impassable;
if ( (surface || impassable) && (staticTiles[i].Z + id.CalcHeight) > z && (z + 16) > staticTiles[i].Z )
return false;
else if ( surface && !impassable && z == (staticTiles[i].Z + id.CalcHeight) )
hasSurface = true;
}
Sector sector = map.GetSector( x, y );
ArrayList items = sector.Items;
for ( int i = 0; i < items.Count; ++i )
{
Item item = (Item)items[i];
if ( item.AtWorldPoint( x, y ) )
{
ItemData id = item.ItemData;
surface = id.Surface;
impassable = id.Impassable;
if ( (surface || impassable) && (item.Z + id.CalcHeight) > z && (z + 16) > item.Z )
return false;
else if ( surface && !impassable && z == (item.Z + id.CalcHeight) )
hasSurface = true;
}
}
return hasSurface;
}
private static void RecurseFindFloor( Map map, int x, int y, ArrayList floor )
{
Point2D p = new Point2D( x, y );
if ( floor.Contains( p ) )
return;
floor.Add( p );
for ( int xo = -1; xo <= 1; ++xo )
{
for ( int yo = -1; yo <= 1; ++yo )
{
if ( (xo != 0 || yo != 0) && IsFloor( map, x + xo, y + yo, false ) )
RecurseFindFloor( map, x + xo, y + yo, floor );
}
}
}
}
}