package org.mctourney.autoreferee.goals;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.jdom2.Element;
import org.mctourney.autoreferee.AutoRefMatch;
import org.mctourney.autoreferee.AutoRefTeam;
import org.mctourney.autoreferee.util.BlockData;
import org.mctourney.autoreferee.util.LocationUtil;
/**
* Represents a block placement goal.
*
* @author authorblues
*/
public class BlockGoal extends AutoRefGoal
{
private Location loc;
private BlockData blockdata;
private int range;
private String customName = null;
private boolean canCraft = false;
/**
* Constructs a team's win condition.
*
* @param team owner of this win condition
* @param loc target location for objective
* @param blockdata objective block type
* @param range maximum allowed distance from target
*/
public BlockGoal(AutoRefTeam team, Location loc, BlockData blockdata, int range)
{ super(team); this.loc = loc; this.blockdata = blockdata; this.range = range; }
private BlockGoal(AutoRefTeam team, BlockGoal goal)
{ this(team, goal.loc, goal.blockdata, goal.range); }
/**
* Constructs a team's win condition.
*
* @param team owner of this win condition
* @param loc target location for objective
* @param blockdata objective block type
*/
public BlockGoal(AutoRefTeam team, Location loc, BlockData blockdata)
{ this(team, loc, blockdata, team.getMatch().getInexactRange()); }
/**
* Constructs a team's win condition.
*
* @param team owner of this win condition
* @param block block to construct win condition from
* @param range maximum allowed distance from target
*/
public BlockGoal(AutoRefTeam team, Block block, int range)
{ super(team); this.loc = block.getLocation(); this.blockdata = BlockData.fromBlock(block); this.range = range; }
/**
* Constructs a team's win condition.
*
* @param team owner of this win condition
* @param block block to construct win condition from
*/
public BlockGoal(AutoRefTeam team, Block block)
{ this(team, block, team.getMatch().getInexactRange()); }
public BlockGoal(AutoRefTeam team, Element elt)
{
super(team);
this.loc = LocationUtil.fromCoords(team.getMatch().getWorld(),
elt.getAttributeValue("pos"));
this.blockdata = BlockData.unserialize(elt.getAttributeValue("id"));
String arange = elt.getAttributeValue("range");
if (arange != null && !arange.isEmpty())
range = Integer.parseInt(arange);
else range = team.getMatch().getInexactRange();
String acraft = elt.getAttributeValue("craftable");
this.canCraft = (acraft != null && Boolean.parseBoolean(acraft));
String text = elt.getTextTrim();
if (text != null && !text.isEmpty())
customName = text;
}
@Override
public BlockGoal copy()
{ return this.copy(this.owner); }
@Override
public BlockGoal copy(AutoRefTeam team)
{ return new BlockGoal(team, this); }
@Override
public Element toElement()
{
Element elt = new Element("block");
if (this.customName != null)
elt.setText(this.customName);
elt.setAttribute("pos", LocationUtil.toBlockCoords(this.loc));
elt.setAttribute("id", this.blockdata.serialize());
if (this.range != getOwner().getMatch().getInexactRange())
elt.setAttribute("range", Integer.toString(this.range));
if (this.canCraft)
elt.setAttribute("craftable", Boolean.toString(this.canCraft));
return elt;
}
@Override
public boolean isSatisfied(AutoRefMatch match)
{ return null != blockInRange(blockdata, loc, range); }
@Override
public double getScore(AutoRefMatch match)
{ return getItemStatus().value; }
/**
* Checks if a given block type exists within a cube centered around a location.
*
* @param blockdata block type being searched for
* @param loc center point of searchable cube
* @param radius radius of searchable cube
* @return location of a matching block within the region if one exists, otherwise null
*/
public static Location blockInRange(BlockData blockdata, Location loc, int radius)
{
Block b = loc.getBlock();
int h = loc.getWorld().getMaxHeight();
int by = loc.getBlockY();
for (int y = -radius; y <= radius; ++y) if (by + y >= 0 && by + y < h)
for (int x = -radius; x <= radius; ++x)
for (int z = -radius; z <= radius; ++z)
{
Block rel = b.getRelative(x, y, z);
if (blockdata.matchesBlock(rel)) return rel.getLocation();
}
return null;
}
/**
* Checks if a given block type exists within a cube centered around a location.
*
* @param goal win condition object
* @return location of a matching block within the region if one exists, otherwise null
*/
public static Location blockInRange(BlockGoal goal)
{ return blockInRange(goal.getItem(), goal.getTarget(), goal.getInexactRange()); }
@Override
public void updateReferee(Player ref)
{
String bd = getItem().serialize();
AutoRefMatch.messageReferee(ref, "team", getOwner().getName(), "goal", "+" + bd);
AutoRefMatch.messageReferee(ref, "team", getOwner().getName(), "state", bd,
getItemStatus().toString());
}
/**
* Gets the target location for this objective.
*/
@Override
public Location getTarget()
{ return loc; }
/**
* Gets the block type for this objective.
*/
@Override
public BlockData getItem()
{ return blockdata; }
@Override
public boolean canCraftItem()
{ return canCraft; }
@Override
public String toString()
{
String nm = customName == null ? blockdata.getDisplayName() : customName;
return String.format("%s @ %s", nm, LocationUtil.toBlockCoords(loc));
}
/**
* Gets the maximum range this objective may be placed from its target.
*/
public int getInexactRange()
{ return range; }
}