mirror of
https://github.com/ACEmulator/ACE
synced 2026-08-17 12:26:06 -04:00
* Adding multistrike weapons * Adding two-handed weapons cleaving * Adding PropertyInt.Cleaving, and support for multiple cleave targets * Adding no weapon check
168 lines
5.7 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|