ace/Source/ACE.Server/Entity/PositionExtensions.cs
gmriggs eb2eb029f1 Adding two-handed weapons cleaving (#1044)
* Adding multistrike weapons

* Adding two-handed weapons cleaving

* Adding PropertyInt.Cleaving, and support for multiple cleave targets

* Adding no weapon check
2018-10-03 15:03:05 -04:00

168 lines
5.7 KiB
C#

using ACE.Entity;
using System;
using System.Numerics;
using ACE.Server.Physics.Common;
using ACE.Server.Physics.Extensions;
using ACE.Server.Physics.Util;
using Position = ACE.Entity.Position;
namespace ACE.Server.Entity
{
public static class PositionExtensions
{
public static Vector3 ToGlobal(this Position p)
{
var landblock = LScape.get_landblock(p.LandblockId.Raw);
if (landblock.IsDungeon)
return p.Pos;
var x = p.LandblockId.LandblockX * Position.BlockLength + p.PositionX;
var y = p.LandblockId.LandblockY * Position.BlockLength + p.PositionY;
var z = p.PositionZ;
return new Vector3(x, y, z);
}
public static Position FromGlobal(this Position p, Vector3 pos)
{
var landblock = LScape.get_landblock(p.LandblockId.Raw);
if (landblock.IsDungeon)
{
var iPos = new Position();
iPos.LandblockId = p.LandblockId;
iPos.Pos = new Vector3(pos.X, pos.Y, pos.Z);
iPos.Rotation = p.Rotation;
iPos.LandblockId = new LandblockId(GetCell(iPos));
return iPos;
}
var blockX = (uint)pos.X / Position.BlockLength;
var blockY = (uint)pos.Y / Position.BlockLength;
var localX = pos.X % Position.BlockLength;
var localY = pos.Y % Position.BlockLength;
var landblockID = blockX << 24 | blockY << 16 | 0xFFFF;
var position = new Position();
position.LandblockId = new LandblockId((byte)blockX, (byte)blockY);
position.PositionX = localX;
position.PositionY = localY;
position.PositionZ = pos.Z;
position.Rotation = p.Rotation;
position.LandblockId = new LandblockId(GetCell(position));
return position;
}
/// <summary>
/// Gets the cell ID for a position within a landblock
/// </summary>
public static uint GetCell(this Position p)
{
var landblock = LScape.get_landblock(p.LandblockId.Raw);
// dungeons
if (landblock.IsDungeon)
return GetIndoorCell(p);
// outside - could be on landscape, in building, or underground cave
var cellID = GetOutdoorCell(p);
var landcell = (LandCell)LScape.get_landcell(cellID);
if (landcell.has_building())
{
var envCells = landcell.Building.get_building_cells();
foreach (var envCell in envCells)
if (envCell.point_in_cell(p.Pos))
return envCell.ID;
}
// handle underground areas ie. caves
// get the terrain Z-height for this X/Y
Physics.Polygon walkable = null;
var terrainPoly = landcell.find_terrain_poly(p.Pos, ref walkable);
if (walkable != null)
{
Vector3 terrainPos = p.Pos;
walkable.Plane.set_height(ref terrainPos);
// are we below ground? if so, search all of the indoor cells for this landblock
if (terrainPos.Z > p.Pos.Z)
{
var envCells = landblock.get_envcells();
foreach (var envCell in envCells)
if (envCell.point_in_cell(p.Pos))
return envCell.ID;
}
}
return cellID;
}
/// <summary>
/// Gets an outdoor cell ID for a position within a landblock
/// </summary>
private static uint GetOutdoorCell(this Position p)
{
var cellX = (uint)p.PositionX / Position.CellLength;
var cellY = (uint)p.PositionY / Position.CellLength;
var cellID = cellX * Position.CellSide + cellY + 1;
var blockCellID = (uint)((p.LandblockId.Raw & 0xFFFF0000) | cellID);
return blockCellID;
}
/// <summary>
/// Gets an indoor cell ID for a position within a dungeon
/// </summary>
private static uint GetIndoorCell(this Position p)
{
var adjustCell = AdjustCell.Get(p.Landblock);
var envCell = adjustCell.GetCell(p.Pos);
if (envCell != null)
return envCell.Value;
else
return p.Cell;
}
/// <summary>
/// Returns the greatest single-dimension square distance between 2 positions
/// </summary>
public static uint CellDist(this Position p1, Position p2)
{
if (!p1.Indoors && !p2.Indoors)
{
return Math.Max(p1.GlobalCellX, p1.GlobalCellY);
}
// handle dungeons
/*var block1 = LScape.get_landblock(p1.LandblockId.Raw);
var block2 = LScape.get_landblock(p2.LandblockId.Raw);
if (block1.IsDungeon || block2.IsDungeon)
{
// 2 separate dungeons = infinite distance
if (block1.ID != block2.ID)
return uint.MaxValue;
return GetDungeonCellDist(p1, p2);
}*/
var _p1 = new Position(p1);
var _p2 = new Position(p2);
if (_p1.Indoors)
_p1.LandblockId = new LandblockId(_p1.GetOutdoorCell());
if (_p2.Indoors)
_p2.LandblockId = new LandblockId(_p2.GetIndoorCell());
return Math.Max(_p1.GlobalCellX, _p2.GlobalCellY);
}
public static uint GetDungeonCellDist(Position p1, Position p2)
{
// not implemented yet
return uint.MaxValue;
}
}
}