package Roguelike.Entity.AI.BehaviourTree.Actions; import Roguelike.Entity.AI.BehaviourTree.BehaviourTree.BehaviourTreeState; import Roguelike.Entity.GameEntity; import Roguelike.Entity.Tasks.TaskMove; import Roguelike.Global; import Roguelike.Global.Direction; import Roguelike.Global.Passability; import Roguelike.Global.Statistic; import Roguelike.Items.Item; import Roguelike.Items.Item.EquipmentSlot; import Roguelike.Pathfinding.Pathfinder; import Roguelike.Tiles.GameTile; import Roguelike.Tiles.Point; import Roguelike.Util.EnumBitflag; import com.badlogic.gdx.math.Matrix3; import com.badlogic.gdx.math.Vector3; import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.XmlReader.Element; import java.util.Iterator; public class ActionMoveToAttack extends AbstractAction { // ---------------------------------------------------------------------- public static final EnumBitflag<Passability> WeaponPassability = new EnumBitflag<Passability>( Passability.LEVITATE ); public String key; @Override public BehaviourTreeState evaluate( GameEntity entity ) { Point target = (Point) getData( key, null ); // if no target, fail if ( target == null ) { State = BehaviourTreeState.FAILED; return State; } Array<Point> possibleTiles = new Array<Point>(); Item weapon = entity.getInventory().getEquip( EquipmentSlot.WEAPON ); if (weapon != null && weapon.wepDef != null) { for (Direction dir : Direction.values()) { if ( ( Global.CanMoveDiagonal || dir.isCardinal() ) && dir != Direction.CENTER ) { // For each direction, find the attack points Matrix3 mat = new Matrix3(); mat.setToRotation( dir.getAngle() ); Vector3 vec = new Vector3(); for (Point p : weapon.wepDef.hitPoints) { vec.set(p.x, p.y, 0); vec.mul( mat ); int dx = Math.round( vec.x ); int dy = Math.round( vec.y ); Point newPos = Global.PointPool.obtain().set( target.x - dx, target.y - dy ); GameTile tile = entity.tile[0][0].level.getGameTile( newPos ); if ( tile != null && tile.entity == null && tile.getPassable( entity.getTravelType(), entity ) ) { possibleTiles.add( newPos ); } } } } } else { for ( Direction dir : Direction.values() ) { if ( ( Global.CanMoveDiagonal || dir.isCardinal() ) && dir != Direction.CENTER ) { Point newPos = Global.PointPool.obtain().set( target.x + dir.getX(), target.y + dir.getY() ); GameTile tile = entity.tile[0][0].level.getGameTile( newPos ); if ( tile != null && tile.entity == null && tile.getPassable( entity.getTravelType(), entity ) ) { possibleTiles.add( newPos ); } } } } Array<Point> shadowCast = null; GameTile targetTile = entity.tile[0][0].level.getGameTile( target ); if (targetTile.entity != null) { shadowCast = targetTile.entity.visibilityCache.getCurrentShadowCast(); } else if (targetTile.environmentEntity != null) { targetTile.environmentEntity.updateShadowCast(); shadowCast = targetTile.environmentEntity.visibilityCache.getCurrentShadowCast(); } else { // Theres nothing there to attack, so give up State = BehaviourTreeState.FAILED; return State; } // minimise possible tiles Iterator<Point> itr = possibleTiles.iterator(); while (itr.hasNext()) { Point p = itr.next(); boolean found = false; for (Point visibleP : shadowCast) { if (visibleP.x == p.x && visibleP.y == p.y) { found = true; break; } } if (!found) { itr.remove(); } } int bestDist = Integer.MAX_VALUE; Array<Point> bestPath = null; for ( Point pos : possibleTiles ) { if ( pos.x == entity.tile[0][0].x && pos.y == entity.tile[0][0].y ) { Global.PointPool.freeAll( possibleTiles ); State = BehaviourTreeState.SUCCEEDED; return State; } Pathfinder pathFinder = new Pathfinder( entity.tile[0][0].level.getGrid(), entity.tile[0][0].x, entity.tile[0][0].y, pos.x, pos.y, Global.CanMoveDiagonal, entity.size, entity ); Array<Point> path = pathFinder.getPath( entity.getTravelType() ); if ( path.size > 1 && path.size < bestDist && path.size < 20 ) { if ( entity.tile[0][0].level.getGameTile( path.get( 1 ) ).getPassable( entity.getTravelType(), entity ) ) { bestDist = path.size; if ( bestPath != null ) { Global.PointPool.freeAll( bestPath ); } bestPath = path; } } } Global.PointPool.freeAll( possibleTiles ); if ( bestPath == null ) { State = BehaviourTreeState.FAILED; return State; } int[] offset = new int[] { bestPath.get( 1 ).x - bestPath.get( 0 ).x, bestPath.get( 1 ).y - bestPath.get( 0 ).y }; Global.PointPool.freeAll( bestPath ); entity.tasks.add( new TaskMove( Direction.getDirection( offset ) ) ); State = BehaviourTreeState.RUNNING; return State; } @Override public void cancel() { } @Override public void parse( Element xmlElement ) { key = xmlElement.getAttribute( "Key" ); } }