Created
February 22, 2014 19:27
-
-
Save msturgill/9160714 to your computer and use it in GitHub Desktop.
Zenvera HousePlacement.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using Server; | |
using Server.Guilds; | |
using Server.Items; | |
using Server.Misc; | |
using Server.Regions; | |
using Server.Spells; | |
namespace Server.Multis | |
{ | |
public enum HousePlacementResult | |
{ | |
Valid, | |
BadRegion, | |
BadLand, | |
BadStatic, | |
BadItem, | |
NoSurface, | |
BadRegionHidden, | |
BadRegionTemp, | |
InvalidCastleKeep, | |
BadRegionRaffle | |
} | |
public class HousePlacement | |
{ | |
private const int YardSize = 5; | |
// Any land tile which matches one of these ID numbers is considered a road and cannot be placed over. | |
private static int[] m_RoadIDs = new int[] | |
{ | |
0x071, 0x08C, | |
0x0E8, 0x0EB, | |
0x14C, 0x14F, | |
0x161, 0x174, | |
0x1F0, 0x1F3, | |
0x26E, 0x279, | |
0x27E, 0x281, | |
0x324, 0x3AC, | |
0x547, 0x556, | |
0x597, 0x5A6, | |
0x637, 0x63A, | |
0x7AE, 0x7B1, | |
0x442, 0x479, // Sand stones | |
0x501, 0x510, // Sand stones | |
0x009, 0x015, // Furrows | |
0x150, 0x15C // Furrows | |
}; | |
public static HousePlacementResult Check( Mobile from, int multiID, Point3D center, out ArrayList toMove ) | |
{ | |
// If this spot is considered valid, every item and mobile in this list will be moved under the house sign | |
toMove = new ArrayList(); | |
Map map = from.Map; | |
if ( map == null || map == Map.Internal ) | |
return HousePlacementResult.BadLand; // A house cannot go here | |
if ( from.AccessLevel >= AccessLevel.GameMaster ) | |
return HousePlacementResult.Valid; // Staff can place anywhere | |
if ( map == Map.Ilshenar || SpellHelper.IsFeluccaT2A( map, center ) ) | |
return HousePlacementResult.BadRegion; // No houses in Ilshenar/T2A | |
if ( map == Map.Malas && ( multiID == 0x007C || multiID == 0x007E ) ) | |
return HousePlacementResult.InvalidCastleKeep; | |
NoHousingRegion noHousingRegion = (NoHousingRegion) Region.Find( center, map ).GetRegion( typeof( NoHousingRegion ) ); | |
if ( noHousingRegion != null ) | |
return HousePlacementResult.BadRegion; | |
// This holds data describing the internal structure of the house | |
MultiComponentList mcl = MultiData.GetComponents( multiID ); | |
if ( multiID >= 0x13EC && multiID < 0x1D00 ) | |
HouseFoundation.AddStairsTo( ref mcl ); // this is a AOS house, add the stairs | |
// Location of the nortwest-most corner of the house | |
Point3D start = new Point3D( center.X + mcl.Min.X, center.Y + mcl.Min.Y, center.Z ); | |
// These are storage lists. They hold items and mobiles found in the map for further processing | |
List<Item> items = new List<Item>(); | |
List<Mobile> mobiles = new List<Mobile>(); | |
// These are also storage lists. They hold location values indicating the yard and border locations. | |
List<Point2D> yard = new List<Point2D>(), borders = new List<Point2D>(); | |
/* RULES: | |
* | |
* 1) All tiles which are around the -outside- of the foundation must not have anything impassable. | |
* 2) No impassable object or land tile may come in direct contact with any part of the house. | |
* 3) Five tiles from the front and back of the house must be completely clear of all house tiles. | |
* 4) The foundation must rest flatly on a surface. Any bumps around the foundation are not allowed. | |
* 5) No foundation tile may reside over terrain which is viewed as a road. | |
*/ | |
for ( int x = 0; x < mcl.Width; ++x ) | |
{ | |
for ( int y = 0; y < mcl.Height; ++y ) | |
{ | |
int tileX = start.X + x; | |
int tileY = start.Y + y; | |
StaticTile[] addTiles = mcl.Tiles[x][y]; | |
if ( addTiles.Length == 0 ) | |
continue; // There are no tiles here, continue checking somewhere else | |
Point3D testPoint = new Point3D( tileX, tileY, center.Z ); | |
Region reg = Region.Find( testPoint, map ); | |
if ( !reg.AllowHousing( from, testPoint ) ) // Cannot place houses in dungeons, towns, treasure map areas etc | |
{ | |
if ( reg.IsPartOf( typeof( TempNoHousingRegion ) ) ) | |
return HousePlacementResult.BadRegionTemp; | |
if ( reg.IsPartOf( typeof( TreasureRegion ) ) || reg.IsPartOf( typeof( HouseRegion ) ) ) | |
return HousePlacementResult.BadRegionHidden; | |
if ( reg.IsPartOf( typeof( HouseRaffleRegion ) ) ) | |
return HousePlacementResult.BadRegionRaffle; | |
return HousePlacementResult.BadRegion; | |
} | |
LandTile landTile = map.Tiles.GetLandTile( tileX, tileY ); | |
int landID = landTile.ID & TileData.MaxLandValue; | |
StaticTile[] oldTiles = map.Tiles.GetStaticTiles( tileX, tileY, true ); | |
Sector sector = map.GetSector( tileX, tileY ); | |
items.Clear(); | |
for ( int i = 0; i < sector.Items.Count; ++i ) | |
{ | |
Item item = sector.Items[i]; | |
if ( item.Visible && item.X == tileX && item.Y == tileY ) | |
items.Add( item ); | |
} | |
mobiles.Clear(); | |
for ( int i = 0; i < sector.Mobiles.Count; ++i ) | |
{ | |
Mobile m = sector.Mobiles[i]; | |
if ( m.X == tileX && m.Y == tileY ) | |
mobiles.Add( m ); | |
} | |
int landStartZ = 0, landAvgZ = 0, landTopZ = 0; | |
map.GetAverageZ( tileX, tileY, ref landStartZ, ref landAvgZ, ref landTopZ ); | |
bool hasFoundation = false; | |
for ( int i = 0; i < addTiles.Length; ++i ) | |
{ | |
StaticTile addTile = addTiles[i]; | |
if ( addTile.ID == 0x1 ) // Nodraw | |
continue; | |
TileFlag addTileFlags = TileData.ItemTable[addTile.ID & TileData.MaxItemValue].Flags; | |
bool isFoundation = ( addTile.Z == 0 && (addTileFlags & TileFlag.Wall) != 0 ); | |
bool hasSurface = false; | |
if ( isFoundation ) | |
hasFoundation = true; | |
int addTileZ = center.Z + addTile.Z; | |
int addTileTop = addTileZ + addTile.Height; | |
if ( (addTileFlags & TileFlag.Surface) != 0 ) | |
addTileTop += 16; | |
if ( addTileTop > landStartZ && landAvgZ > addTileZ ) | |
return HousePlacementResult.BadLand; // Broke rule #2 | |
if ( isFoundation && ((TileData.LandTable[landTile.ID & TileData.MaxLandValue].Flags & TileFlag.Impassable) == 0) && landAvgZ == center.Z ) | |
hasSurface = true; | |
for ( int j = 0; j < oldTiles.Length; ++j ) | |
{ | |
StaticTile oldTile = oldTiles[j]; | |
ItemData id = TileData.ItemTable[oldTile.ID & TileData.MaxItemValue]; | |
if ( (id.Impassable || (id.Surface && (id.Flags & TileFlag.Background) == 0)) && addTileTop > oldTile.Z && (oldTile.Z + id.CalcHeight) > addTileZ ) | |
return HousePlacementResult.BadStatic; // Broke rule #2 | |
/*else if ( isFoundation && !hasSurface && (id.Flags & TileFlag.Surface) != 0 && (oldTile.Z + id.CalcHeight) == center.Z ) | |
hasSurface = true;*/ | |
} | |
for ( int j = 0; j < items.Count; ++j ) | |
{ | |
Item item = items[j]; | |
ItemData id = item.ItemData; | |
if ( item.Movable /*|| ( item is Guildstone )*/ ) | |
{ | |
//toMove.Add( item ); | |
return HousePlacementResult.BadItem; // Broke new rule: no placing on items (plots must be cleared). | |
} | |
else if ( addTileTop > item.Z && (item.Z + id.CalcHeight) > addTileZ ) | |
{ | |
if ( (id.Impassable || (id.Surface && (id.Flags & TileFlag.Background) == 0)) ) | |
return HousePlacementResult.BadItem; // Broke rule #2 | |
} | |
/*else if ( isFoundation && !hasSurface && (id.Flags & TileFlag.Surface) != 0 && (item.Z + id.CalcHeight) == center.Z ) | |
{ | |
hasSurface = true; | |
}*/ | |
} | |
if ( isFoundation && !hasSurface ) | |
return HousePlacementResult.NoSurface; // Broke rule #4 | |
for ( int j = 0; j < mobiles.Count; ++j ) | |
{ | |
Mobile m = mobiles[j]; | |
if ( addTileTop > m.Z && (m.Z + 16) > addTileZ ) | |
toMove.Add( m ); | |
} | |
} | |
for ( int i = 0; i < m_RoadIDs.Length; i += 2 ) | |
{ | |
if ( landID >= m_RoadIDs[i] && landID <= m_RoadIDs[i + 1] ) | |
return HousePlacementResult.BadLand; // Broke rule #5 | |
} | |
if ( hasFoundation ) | |
{ | |
for ( int xOffset = -1; xOffset <= 1; ++xOffset ) | |
{ | |
for ( int yOffset = -YardSize; yOffset <= YardSize; ++yOffset ) | |
{ | |
Point2D yardPoint = new Point2D( tileX + xOffset, tileY + yOffset ); | |
if ( !yard.Contains( yardPoint ) ) | |
yard.Add( yardPoint ); | |
} | |
} | |
for ( int xOffset = -1; xOffset <= 1; ++xOffset ) | |
{ | |
for ( int yOffset = -1; yOffset <= 1; ++yOffset ) | |
{ | |
if ( xOffset == 0 && yOffset == 0 ) | |
continue; | |
// To ease this rule, we will not add to the border list if the tile here is under a base floor (z<=8) | |
int vx = x + xOffset; | |
int vy = y + yOffset; | |
if ( vx >= 0 && vx < mcl.Width && vy >= 0 && vy < mcl.Height ) | |
{ | |
StaticTile[] breakTiles = mcl.Tiles[vx][vy]; | |
bool shouldBreak = false; | |
for ( int i = 0; !shouldBreak && i < breakTiles.Length; ++i ) | |
{ | |
StaticTile breakTile = breakTiles[i]; | |
if ( breakTile.Height == 0 && breakTile.Z <= 8 && TileData.ItemTable[breakTile.ID & TileData.MaxItemValue].Surface ) | |
shouldBreak = true; | |
} | |
if ( shouldBreak ) | |
continue; | |
} | |
Point2D borderPoint = new Point2D( tileX + xOffset, tileY + yOffset ); | |
if ( !borders.Contains( borderPoint ) ) | |
borders.Add( borderPoint ); | |
} | |
} | |
} | |
} | |
} | |
for ( int i = 0; i < borders.Count; ++i ) | |
{ | |
Point2D borderPoint = borders[i]; | |
LandTile landTile = map.Tiles.GetLandTile( borderPoint.X, borderPoint.Y ); | |
int landID = landTile.ID & TileData.MaxLandValue; | |
if ( (TileData.LandTable[landID].Flags & TileFlag.Impassable) != 0 ) | |
return HousePlacementResult.BadLand; | |
for ( int j = 0; j < m_RoadIDs.Length; j += 2 ) | |
{ | |
if ( landID >= m_RoadIDs[j] && landID <= m_RoadIDs[j + 1] ) | |
return HousePlacementResult.BadLand; // Broke rule #5 | |
} | |
StaticTile[] tiles = map.Tiles.GetStaticTiles( borderPoint.X, borderPoint.Y, true ); | |
for ( int j = 0; j < tiles.Length; ++j ) | |
{ | |
StaticTile tile = tiles[j]; | |
ItemData id = TileData.ItemTable[tile.ID & TileData.MaxItemValue]; | |
if ( id.Impassable || (id.Surface && (id.Flags & TileFlag.Background) == 0 && (tile.Z + id.CalcHeight) > (center.Z + 2)) ) | |
return HousePlacementResult.BadStatic; // Broke rule #1 | |
} | |
Sector sector = map.GetSector( borderPoint.X, borderPoint.Y ); | |
List<Item> sectorItems = sector.Items; | |
for ( int j = 0; j < sectorItems.Count; ++j ) | |
{ | |
Item item = sectorItems[j]; | |
if ( item.X != borderPoint.X || item.Y != borderPoint.Y /*|| item.Movable*/ ) | |
continue; | |
ItemData id = item.ItemData; | |
if ( item.Movable || id.Impassable || (id.Surface && (id.Flags & TileFlag.Background) == 0 && (item.Z + id.CalcHeight) > (center.Z + 2)) ) | |
return HousePlacementResult.BadItem; // Broke rule #1 | |
} | |
} | |
List<Sector> _sectors = new List<Sector>(); | |
List<BaseHouse> _houses = new List<BaseHouse>(); | |
for ( int i = 0; i < yard.Count; i++ ) { | |
Sector sector = map.GetSector( yard[i] ); | |
if ( !_sectors.Contains( sector ) ) { | |
_sectors.Add( sector ); | |
if ( sector.Multis != null ) { | |
for ( int j = 0; j < sector.Multis.Count; j++ ) { | |
if ( sector.Multis[j] is BaseHouse ) { | |
BaseHouse _house = (BaseHouse)sector.Multis[j]; | |
if ( !_houses.Contains( _house ) ) { | |
_houses.Add( _house ); | |
} | |
} | |
} | |
} | |
} | |
} | |
for ( int i = 0; i < yard.Count; ++i ) | |
{ | |
foreach ( BaseHouse b in _houses ) { | |
if ( b.Contains( yard[i] ) ) | |
return HousePlacementResult.BadStatic; // Broke rule #3 | |
} | |
/*Point2D yardPoint = yard[i]; | |
IPooledEnumerable eable = map.GetMultiTilesAt( yardPoint.X, yardPoint.Y ); | |
foreach ( StaticTile[] tile in eable ) | |
{ | |
for ( int j = 0; j < tile.Length; ++j ) | |
{ | |
if ( (TileData.ItemTable[tile[j].ID & TileData.MaxItemValue].Flags & (TileFlag.Impassable | TileFlag.Surface)) != 0 ) | |
{ | |
eable.Free(); | |
return HousePlacementResult.BadStatic; // Broke rule #3 | |
} | |
} | |
} | |
eable.Free();*/ | |
} | |
return HousePlacementResult.Valid; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment