goes with the commit below VVVV
This commit is contained in:
parent
d3452772ed
commit
ed8d9459b2
@ -0,0 +1,130 @@
|
||||
package mineplex.game.clans.clans.outpost;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Skeleton;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
|
||||
import mineplex.core.common.util.UtilEnt;
|
||||
import mineplex.core.common.util.UtilMath;
|
||||
import mineplex.core.common.util.UtilPlayer;
|
||||
import mineplex.core.disguise.disguises.DisguisePlayer;
|
||||
import mineplex.game.clans.clans.outpost.pathing.AStar;
|
||||
import mineplex.game.clans.clans.outpost.pathing.AStar.InvalidPathException;
|
||||
import mineplex.game.clans.clans.outpost.pathing.PathingResult;
|
||||
import mineplex.game.clans.clans.outpost.pathing.Tile;
|
||||
|
||||
public class OutpostBuilder
|
||||
{
|
||||
private Skeleton _entity;
|
||||
|
||||
private List<Location> _path;
|
||||
private int _pathPos;
|
||||
private List<Location> _moveLocations;
|
||||
private int _nextLocation;
|
||||
private long _arrivedTime;
|
||||
private long _lastMovement;
|
||||
|
||||
private Outpost _host;
|
||||
|
||||
public OutpostBuilder(Location pos, String name, List<Location> locations, Outpost host)
|
||||
{
|
||||
_host = host;
|
||||
|
||||
Location spawnLoc = pos;
|
||||
Skeleton skel = pos.getWorld().spawn(spawnLoc, Skeleton.class);
|
||||
skel.teleport(spawnLoc);
|
||||
skel.setHealth(20);
|
||||
UtilEnt.Vegetate(skel);
|
||||
UtilEnt.silence(skel, true);
|
||||
|
||||
skel.getEquipment().setHelmet(new ItemStack(Material.NETHER_BRICK_ITEM, 1));
|
||||
skel.getEquipment().setItemInHand(new ItemStack(Material.IRON_PICKAXE, 1));
|
||||
|
||||
// Get in range
|
||||
List<Player> inRange = UtilPlayer.getNearby(spawnLoc, 75d);
|
||||
|
||||
// Disguise
|
||||
DisguisePlayer disguise = new DisguisePlayer(skel, new GameProfile(Bukkit.getOfflinePlayer("Chiss").getUniqueId(), "Chiss"));
|
||||
host.getClan().Clans.getDisguiseManager().disguise(disguise, inRange.toArray(new Player[inRange.size()]));
|
||||
|
||||
_entity = skel;
|
||||
|
||||
_moveLocations = locations;
|
||||
}
|
||||
|
||||
public void tick()
|
||||
{
|
||||
if (_path == null || _arrivedTime != -1)
|
||||
{
|
||||
_nextLocation = UtilMath.random.nextInt(_moveLocations.size());
|
||||
_path = calculatePath();
|
||||
_pathPos = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (System.currentTimeMillis() - _lastMovement >= 500)
|
||||
{
|
||||
if (_pathPos == _path.size() - 1)
|
||||
{
|
||||
_arrivedTime = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
_entity.teleport(_path.get(++_pathPos));
|
||||
_arrivedTime = -1;
|
||||
}
|
||||
|
||||
_lastMovement = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
|
||||
private List<Location> calculatePath()
|
||||
{
|
||||
Location start = _entity.getLocation();
|
||||
Location end = _moveLocations.get(_nextLocation);
|
||||
int range = _host._type._size * 2;
|
||||
|
||||
try
|
||||
{
|
||||
AStar pathFinder = new AStar(start, end, range);
|
||||
ArrayList<Tile> route = pathFinder.iterate();
|
||||
PathingResult res = pathFinder.getPathingResult();
|
||||
|
||||
if (res == PathingResult.NO_PATH)
|
||||
{
|
||||
return Arrays.asList(_moveLocations.get(_nextLocation));
|
||||
}
|
||||
|
||||
List<Location> list = new ArrayList<>();
|
||||
|
||||
for (Tile tile : route)
|
||||
{
|
||||
list.add(tile.getLocation(start));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
catch (InvalidPathException e)
|
||||
{
|
||||
cleanup();
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanup()
|
||||
{
|
||||
_entity.remove();
|
||||
_host.queueForRemoval(this);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,391 @@
|
||||
/*
|
||||
* By @Adamki11s
|
||||
*/
|
||||
|
||||
package mineplex.game.clans.clans.outpost.pathing;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.material.Gate;
|
||||
|
||||
/**
|
||||
* Not made by meee (NewGarbo)
|
||||
* https://bukkit.org/threads/lib-a-pathfinding-algorithm.129786/
|
||||
*/
|
||||
public class AStar
|
||||
{
|
||||
private final int _sx;
|
||||
private final int _sy;
|
||||
private final int _sz;
|
||||
private final int _ex;
|
||||
private final int _ey;
|
||||
private final int _ez;
|
||||
private final World _world;
|
||||
|
||||
private PathingResult _result;
|
||||
|
||||
private HashMap<String, Tile> _open = new HashMap<String, Tile>();
|
||||
private HashMap<String, Tile> _closed = new HashMap<String, Tile>();
|
||||
|
||||
private void addToOpenList(Tile t, boolean modify)
|
||||
{
|
||||
if (_open.containsKey(t.getUID()))
|
||||
{
|
||||
if (modify)
|
||||
{
|
||||
_open.put(t.getUID(), t);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_open.put(t.getUID(), t);
|
||||
}
|
||||
}
|
||||
|
||||
private void addToClosedList(Tile t)
|
||||
{
|
||||
if (!_closed.containsKey(t.getUID()))
|
||||
{
|
||||
_closed.put(t.getUID(), t);
|
||||
}
|
||||
}
|
||||
|
||||
private final int _range;
|
||||
private final String _endUID;
|
||||
|
||||
public AStar(Location start, Location end, int range) throws InvalidPathException
|
||||
{
|
||||
boolean s = true, e = true;
|
||||
|
||||
if (!(s = isLocationWalkable(start)) || !(e = isLocationWalkable(end)))
|
||||
{
|
||||
throw new InvalidPathException(s, e);
|
||||
}
|
||||
|
||||
_world = start.getWorld();
|
||||
_sx = start.getBlockX();
|
||||
_sy = start.getBlockY();
|
||||
_sz = start.getBlockZ();
|
||||
_ex = end.getBlockX();
|
||||
_ey = end.getBlockY();
|
||||
_ez = end.getBlockZ();
|
||||
|
||||
_range = range;
|
||||
|
||||
short sh = 0;
|
||||
Tile t = new Tile(sh, sh, sh, null);
|
||||
t.calculateBoth(_sx, _sy, _sz, _ex, _ey, _ez, true);
|
||||
_open.put(t.getUID(), t);
|
||||
processAdjacentTiles(t);
|
||||
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append(_ex - _sx).append(_ey - _sy).append(_ez - _sz);
|
||||
_endUID = b.toString();
|
||||
}
|
||||
|
||||
public Location getEndLocation()
|
||||
{
|
||||
return new Location(_world, _ex, _ey, _ez);
|
||||
}
|
||||
|
||||
public PathingResult getPathingResult()
|
||||
{
|
||||
return _result;
|
||||
}
|
||||
|
||||
protected boolean _checkOnce = false;
|
||||
|
||||
private int abs(int i)
|
||||
{
|
||||
return (i < 0 ? -i : i);
|
||||
}
|
||||
|
||||
public ArrayList<Tile> iterate()
|
||||
{
|
||||
if (!_checkOnce)
|
||||
{
|
||||
// invert the boolean flag
|
||||
_checkOnce ^= true;
|
||||
if ((abs(_sx - _ex) > _range) || (abs(_sy - _ey) > _range) || (abs(_sz - _ez) > _range))
|
||||
{
|
||||
_result = PathingResult.NO_PATH;
|
||||
return null;// jump out
|
||||
}
|
||||
}
|
||||
// while not at end
|
||||
Tile current = null;
|
||||
|
||||
while (canContinue())
|
||||
{
|
||||
|
||||
// get lowest F cost square on open list
|
||||
current = getLowestFTile();
|
||||
|
||||
// process tiles
|
||||
processAdjacentTiles(current);
|
||||
}
|
||||
|
||||
if (_result != PathingResult.SUCCESS)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
// path found
|
||||
LinkedList<Tile> routeTrace = new LinkedList<Tile>();
|
||||
Tile parent;
|
||||
|
||||
routeTrace.add(current);
|
||||
|
||||
while ((parent = current.getParent()) != null)
|
||||
{
|
||||
routeTrace.add(parent);
|
||||
current = parent;
|
||||
}
|
||||
|
||||
Collections.reverse(routeTrace);
|
||||
|
||||
return new ArrayList<Tile>(routeTrace);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean canContinue()
|
||||
{
|
||||
// check if open list is empty, if it is no path has been found
|
||||
if (_open.size() == 0)
|
||||
{
|
||||
_result = PathingResult.NO_PATH;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_closed.containsKey(_endUID))
|
||||
{
|
||||
_result = PathingResult.SUCCESS;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Tile getLowestFTile()
|
||||
{
|
||||
double f = 0;
|
||||
Tile drop = null;
|
||||
|
||||
// get lowest F cost square
|
||||
for (Tile t : _open.values())
|
||||
{
|
||||
if (f == 0)
|
||||
{
|
||||
t.calculateBoth(_sx, _sy, _sz, _ex, _ey, _ez, true);
|
||||
f = t.getF();
|
||||
drop = t;
|
||||
}
|
||||
else
|
||||
{
|
||||
t.calculateBoth(_sx, _sy, _sz, _ex, _ey, _ez, true);
|
||||
double posF = t.getF();
|
||||
if (posF < f)
|
||||
{
|
||||
f = posF;
|
||||
drop = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// drop from open list and add to closed
|
||||
|
||||
_open.remove(drop.getUID());
|
||||
addToClosedList(drop);
|
||||
|
||||
return drop;
|
||||
}
|
||||
|
||||
private boolean isOnClosedList(Tile t)
|
||||
{
|
||||
return _closed.containsKey(t.getUID());
|
||||
}
|
||||
|
||||
// pass in the current tile as the parent
|
||||
private void processAdjacentTiles(Tile current)
|
||||
{
|
||||
|
||||
// set of possible walk to locations adjacent to current tile
|
||||
HashSet<Tile> possible = new HashSet<Tile>(26);
|
||||
|
||||
for (byte x = -1; x <= 1; x++)
|
||||
{
|
||||
for (byte y = -1; y <= 1; y++)
|
||||
{
|
||||
for (byte z = -1; z <= 1; z++)
|
||||
{
|
||||
|
||||
if (x == 0 && y == 0 && z == 0)
|
||||
{
|
||||
continue;// don't check current square
|
||||
}
|
||||
|
||||
Tile t = new Tile((short) (current.getX() + x), (short) (current.getY() + y), (short) (current.getZ() + z), current);
|
||||
|
||||
if (!t.isInRange(_range))
|
||||
{
|
||||
// if block is out of bounds continue
|
||||
continue;
|
||||
}
|
||||
|
||||
if (x != 0 && z != 0 && (y == 0 || y == 1))
|
||||
{
|
||||
// check to stop jumping through diagonal blocks
|
||||
Tile xOff = new Tile((short) (current.getX() + x), (short) (current.getY() + y), (short) (current.getZ()), current), zOff = new Tile((short) (current.getX()), (short) (current.getY() + y), (short) (current.getZ() + z), current);
|
||||
if (!isTileWalkable(xOff) && !isTileWalkable(zOff))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (isOnClosedList(t))
|
||||
{
|
||||
// ignore tile
|
||||
continue;
|
||||
}
|
||||
|
||||
// only process the tile if it can be walked on
|
||||
if (isTileWalkable(t))
|
||||
{
|
||||
t.calculateBoth(_sx, _sy, _sz, _ex, _ey, _ez, true);
|
||||
possible.add(t);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Tile t : possible)
|
||||
{
|
||||
// get the reference of the object in the array
|
||||
Tile openRef = null;
|
||||
if ((openRef = isOnOpenList(t)) == null)
|
||||
{
|
||||
// not on open list, so add
|
||||
addToOpenList(t, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// is on open list, check if path to that square is better using
|
||||
// G cost
|
||||
if (t.getG() < openRef.getG())
|
||||
{
|
||||
// if current path is better, change parent
|
||||
openRef.setParent(current);
|
||||
// force updates of F, G and H values.
|
||||
openRef.calculateBoth(_sx, _sy, _sz, _ex, _ey, _ez, true);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Tile isOnOpenList(Tile t)
|
||||
{
|
||||
return (_open.containsKey(t.getUID()) ? _open.get(t.getUID()) : null);
|
||||
/*
|
||||
* for (Tile o : open) { if (o.equals(t)) { return o; } } return null;
|
||||
*/
|
||||
}
|
||||
|
||||
private boolean isTileWalkable(Tile t)
|
||||
{
|
||||
Location l = new Location(_world, (_sx + t.getX()), (_sy + t.getY()), (_sz + t.getZ()));
|
||||
Block b = l.getBlock();
|
||||
int i = b.getTypeId();
|
||||
|
||||
// lava, fire, wheat and ladders cannot be walked on, and of course air
|
||||
// 85, 107 and 113 stops npcs climbing fences and fence gates
|
||||
if (i != 10 && i != 11 && i != 51 && i != 59 && i != 65 && i != 0 && i != 85 && i != 107 && i != 113 && !canBlockBeWalkedThrough(i))
|
||||
{
|
||||
// make sure the blocks above are air
|
||||
|
||||
if (b.getRelative(0, 1, 0).getTypeId() == 107)
|
||||
{
|
||||
// fench gate check, if closed continue
|
||||
Gate g = new Gate(b.getRelative(0, 1, 0).getData());
|
||||
return (g.isOpen() ? (b.getRelative(0, 2, 0).getTypeId() == 0) : false);
|
||||
}
|
||||
return (canBlockBeWalkedThrough(b.getRelative(0, 1, 0).getTypeId()) && b.getRelative(0, 2, 0).getTypeId() == 0);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isLocationWalkable(Location l)
|
||||
{
|
||||
Block b = l.getBlock();
|
||||
int i = b.getTypeId();
|
||||
|
||||
if (i != 10 && i != 11 && i != 51 && i != 59 && i != 65 && i != 0 && !canBlockBeWalkedThrough(i))
|
||||
{
|
||||
// make sure the blocks above are air or can be walked through
|
||||
return (canBlockBeWalkedThrough(b.getRelative(0, 1, 0).getTypeId()) && b.getRelative(0, 2, 0).getTypeId() == 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean canBlockBeWalkedThrough(int id)
|
||||
{
|
||||
return (id == 0 || id == 6 || id == 50 || id == 63 || id == 30 || id == 31 || id == 32 || id == 37 || id == 38 || id == 39 || id == 40 || id == 55 || id == 66 || id == 75 || id == 76 || id == 78);
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class InvalidPathException extends Exception
|
||||
{
|
||||
private final boolean _s, _e;
|
||||
|
||||
public InvalidPathException(boolean s, boolean e)
|
||||
{
|
||||
_s = s;
|
||||
_e = e;
|
||||
}
|
||||
|
||||
public String getErrorReason()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (!_s)
|
||||
{
|
||||
sb.append("Start Location was air. ");
|
||||
}
|
||||
if (!_e)
|
||||
{
|
||||
sb.append("End Location was air.");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public boolean isStartNotSolid()
|
||||
{
|
||||
return (!_s);
|
||||
}
|
||||
|
||||
public boolean isEndNotSolid()
|
||||
{
|
||||
return (!_e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package mineplex.game.clans.clans.outpost.pathing;
|
||||
|
||||
/**
|
||||
* Not made by meee (NewGarbo)
|
||||
* https://bukkit.org/threads/lib-a-pathfinding-algorithm.129786/
|
||||
*/
|
||||
public enum PathingResult
|
||||
{
|
||||
SUCCESS(0),
|
||||
NO_PATH(-1);
|
||||
|
||||
private final int _ec;
|
||||
|
||||
PathingResult(int ec)
|
||||
{
|
||||
_ec = ec;
|
||||
}
|
||||
|
||||
public int getEndCode()
|
||||
{
|
||||
return _ec;
|
||||
}
|
||||
}
|
@ -0,0 +1,183 @@
|
||||
/*
|
||||
* By @Adamki11s
|
||||
*/
|
||||
|
||||
package mineplex.game.clans.clans.outpost.pathing;
|
||||
|
||||
import org.bukkit.Location;
|
||||
|
||||
/**
|
||||
* Not made by meee (NewGarbo)
|
||||
* https://bukkit.org/threads/lib-a-pathfinding-algorithm.129786/
|
||||
*/
|
||||
public class Tile
|
||||
{
|
||||
// as offset from starting point
|
||||
private final short _x;
|
||||
private final short _y;
|
||||
private final short _z;
|
||||
|
||||
private double _g = -1;
|
||||
private double _h = -1;
|
||||
|
||||
private Tile _parent = null;
|
||||
|
||||
private final String _uid;
|
||||
|
||||
public Tile(short x, short y, short z, Tile parent)
|
||||
{
|
||||
_x = x;
|
||||
_y = y;
|
||||
_z = z;
|
||||
_parent = parent;
|
||||
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append(x);
|
||||
b.append(y);
|
||||
b.append(z);
|
||||
_uid = b.toString();
|
||||
|
||||
}
|
||||
|
||||
public boolean isInRange(int range)
|
||||
{
|
||||
return ((range - abs(_x) >= 0) && (range - abs(_y) >= 0) && (range - abs(_z) >= 0));
|
||||
}
|
||||
|
||||
public void setParent(Tile parent)
|
||||
{
|
||||
_parent = parent;
|
||||
}
|
||||
|
||||
public Location getLocation(Location start)
|
||||
{
|
||||
return new Location(start.getWorld(), start.getBlockX() + _x, start.getBlockY() + _y, start.getBlockZ() + _z);
|
||||
}
|
||||
|
||||
public Tile getParent()
|
||||
{
|
||||
return _parent;
|
||||
}
|
||||
|
||||
public short getX()
|
||||
{
|
||||
return _x;
|
||||
}
|
||||
|
||||
public int getX(Location i)
|
||||
{
|
||||
return (i.getBlockX() + _x);
|
||||
}
|
||||
|
||||
public short getY()
|
||||
{
|
||||
return _y;
|
||||
}
|
||||
|
||||
public int getY(Location i)
|
||||
{
|
||||
return (i.getBlockY() + _y);
|
||||
}
|
||||
|
||||
public short getZ()
|
||||
{
|
||||
return _z;
|
||||
}
|
||||
|
||||
public int getZ(Location i)
|
||||
{
|
||||
return (i.getBlockZ() + _z);
|
||||
}
|
||||
|
||||
public String getUID()
|
||||
{
|
||||
return _uid;
|
||||
}
|
||||
|
||||
public boolean equals(Tile t)
|
||||
{
|
||||
return (t.getX() == _x && t.getY() == _y && t.getZ() == _z);
|
||||
}
|
||||
|
||||
public void calculateBoth(int sx, int sy, int sz, int ex, int ey, int ez, boolean update)
|
||||
{
|
||||
calculateG(sx, sy, sz, update);
|
||||
calculateH(sx, sy, sz, ex, ey, ez, update);
|
||||
}
|
||||
|
||||
public void calculateH(int sx, int sy, int sz, int ex, int ey, int ez, boolean update)
|
||||
{
|
||||
// only update if h hasn't been calculated or if forced
|
||||
if ((!update && _h == -1) || update)
|
||||
{
|
||||
int hx = sx + _x, hy = sy + _y, hz = sz + _z;
|
||||
_h = getEuclideanDistance(hx, hy, hz, ex, ey, ez);
|
||||
}
|
||||
}
|
||||
|
||||
// G = the movement cost to move from the starting point A to a given square
|
||||
// on the grid, following the path generated to get there.
|
||||
public void calculateG(int sx, int sy, int sz, boolean update)
|
||||
{
|
||||
if ((!update && _g == -1) || update)
|
||||
{
|
||||
// only update if g hasn't been calculated or if forced
|
||||
Tile currentParent = getParent(), currentTile = this;
|
||||
int gCost = 0;
|
||||
// follow path back to start
|
||||
while ((currentParent = currentTile.getParent()) != null)
|
||||
{
|
||||
int dx = currentTile.getX() - currentParent.getX(), dy = currentTile.getY() - currentParent.getY(), dz = currentTile.getZ() - currentParent.getZ();
|
||||
|
||||
dx = abs(dx);
|
||||
dy = abs(dy);
|
||||
dz = abs(dz);
|
||||
|
||||
if (dx == 1 && dy == 1 && dz == 1)
|
||||
{
|
||||
gCost += 1.7;
|
||||
} else if (((dx == 1 || dz == 1) && dy == 1) || ((dx == 1 || dz == 1) && dy == 0))
|
||||
{
|
||||
gCost += 1.4;
|
||||
}
|
||||
else
|
||||
{
|
||||
gCost += 1.0;
|
||||
}
|
||||
|
||||
// move backwards a tile
|
||||
currentTile = currentParent;
|
||||
}
|
||||
_g = gCost;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public double getG()
|
||||
{
|
||||
return _g;
|
||||
}
|
||||
|
||||
public double getH()
|
||||
{
|
||||
return _h;
|
||||
}
|
||||
|
||||
public double getF()
|
||||
{
|
||||
// f = h + g
|
||||
return (_h + _g);
|
||||
}
|
||||
|
||||
private double getEuclideanDistance(int sx, int sy, int sz, int ex, int ey, int ez)
|
||||
{
|
||||
double dx = sx - ex, dy = sy - ey, dz = sz - ez;
|
||||
return Math.sqrt((dx * dx) + (dy * dy) + (dz * dz));
|
||||
}
|
||||
|
||||
private int abs(int i)
|
||||
{
|
||||
return (i < 0 ? -i : i);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user