package com.lucasdnd.ags.map;
import java.util.ArrayList;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.state.StateBasedGame;
import org.newdawn.slick.tiled.TiledMap;
import org.newdawn.slick.util.pathfinding.AStarPathFinder;
import org.newdawn.slick.util.pathfinding.PathFindingContext;
import org.newdawn.slick.util.pathfinding.TileBasedMap;
import com.lucasdnd.ags.gameplay.Asset;
import com.lucasdnd.ags.gameplay.Business;
import com.lucasdnd.ags.gameplay.Character;
import com.lucasdnd.ags.gameplay.Console;
import com.lucasdnd.ags.gameplay.Entity;
import com.lucasdnd.ags.gameplay.Misc;
import com.lucasdnd.ags.gameplay.Shelf;
import com.lucasdnd.ags.gameplay.Table;
import com.lucasdnd.ags.gameplay.Tv;
import com.lucasdnd.ags.map.terrain.Floor;
import com.lucasdnd.ags.map.terrain.Terrain;
import com.lucasdnd.ags.map.terrain.Wall;
import com.lucasdnd.ags.system.MainState;
/**
* A TiledMap subclass to extend its functionality, adding a better data structure to manage the maps.
* @author tulio
*
*/
public class Map extends TiledMap
implements TileBasedMap {
private boolean[][] blocked; // Blocked contain an object blocking it or are located outside the store
private boolean[][] playable; // Playable are available for the player to buy/use
// Layers
public static final int FLOOR = 0;
public static final int LINES = 1;
private GameTile[][] gameTiles; // The Tile Grid that goes on top of the terrain layer
private float xOffset; // Map X Offset
private float yOffset; // Map Y Offset
private int previousXTileAtMouse = -1; // The Tile x that was previously on the player's mouse
private int previousYTileAtMouse = -1; // The Tile y that was previously on the player's mouse
private int xTileAtMouse; // User's current mouse over
private int yTileAtMouse; // User's current mouse over
private final int tileWidth = 32; // Tiles dimensions (size of the Tiles, not size of the Map).
private final int tileHeight = 16; // It is this way so other objects can use the x/y Position calculations
private ArrayList<Wall> walls;
private ArrayList<Floor> floors;
private Tile spawnPoint; // The spawning Tile
private AStarPathFinder pathFinder;
/**
* Creates the map. Reads from Tiled and sets an offset according to the camera
* @param ref
* @param tileSetsLocation
* @param xOffset
* @param yOffset
* @throws SlickException
*/
public Map(String ref, String tileSetsLocation, int xOffset, int yOffset) throws SlickException {
// Starts the base Map
super(ref, tileSetsLocation);
// Defines the X and Y render positions
this.xOffset = xOffset;
this.yOffset = yOffset;
// Creates the Blocked and Playable Tiles
blocked = new boolean[getWidth()][getHeight()];
playable = new boolean[getWidth()][getHeight()];
walls = new ArrayList<Wall>();
floors = new ArrayList<Floor>();
// Creates the Game Tiles
gameTiles = new GameTile[getWidth()][getHeight()];
// Spawn point
spawnPoint = new Tile(13, 13);
// These attributes store the tiles the user is pointing at
xTileAtMouse = 0;
yTileAtMouse = 0;
// PathFinding
pathFinder = new AStarPathFinder(this, super.getWidth() * super.getHeight(), false);
// This will create the map, unblock/block the Tiles and set the polygon Shapes for every Tile
for (int xTile = 0; xTile < getWidth(); xTile++) {
for(int yTile = 0; yTile < getHeight(); yTile++) {
// Read the Tilemap File for Playable Tiles
String playableValue = getTileProperty(getTileId(xTile, yTile, FLOOR), "playable", "false");
playable[xTile][yTile] = playableValue.equals("true");
// Blocked?
blocked[xTile][yTile] = !playable[xTile][yTile];
// Defines the xi and yi relative positions of each polygon
float tileXPos = (tileWidth / 2 * xTile) - (tileWidth / 2 * yTile);
float tileYPos = (tileHeight / 2 * xTile) + (tileHeight / 2 * yTile);
// Math to form the polygon
gameTiles[xTile][yTile] = new GameTile(
// Isometric rendering
tileXPos, tileYPos + tileHeight / 2, // x0, y0
tileXPos + tileWidth / 2, tileYPos, // x1, y1
tileXPos + tileWidth, tileYPos + tileHeight / 2, // x2, y2
tileXPos + tileWidth / 2, tileYPos + tileHeight); // x3, y3
}
}
// Generate the Map walls and floor
updateMapLimits();
}
/**
* Called at every update. Updates the Camera Offset and the highlighted tiles according to mouse over.
* @param container
* @param game
* @param delta
* @param mouseX
* @param mouseY
* @throws SlickException
*/
public void update(int delta, int currentMode, Asset placingAsset,
int mouseX, int mouseY, ArrayList<Table> tables,
boolean leftMouseClicked, boolean leftMouseDown,
Business business) throws SlickException {
// Updates the Tiles Layer
for(int i = 0; i < getWidth(); i++) {
for(int j = 0; j < getHeight(); j++) {
// 1. Update the Offset of the Tiles according to the camera offset
gameTiles[i][j].setxOffset(xOffset);
gameTiles[i][j].setyOffset(yOffset);
// 2. Update the Tiles. This will highlight the Tiles the player has the mouse over
gameTiles[i][j].update(delta, mouseX, mouseY);
// 3. Let the Map know which Tile it is
if(gameTiles[i][j].isMouseOver()) {
xTileAtMouse = i;
yTileAtMouse = j;
}
}
}
// Update the position of the Walls
for (Wall w : walls) {
this.snapToGrid(w);
}
// If the player changed the Mouse Over tile, unhighlight all of them
if(previousXTileAtMouse != xTileAtMouse || previousYTileAtMouse != yTileAtMouse) {
unhighlightAll();
}
/* If the player is trying to place an object on the Map, other tiles should also be highlighted.
/ Here, we check for this situation and apply the highlights accordingly. */
if((currentMode == MainState.BUYING_ASSET || currentMode == MainState.MOVING_ASSET) && placingAsset != null) {
// At first the placement is valid. Down through the method we're going to set it to false if it runs off
// the map or if there's another asset below it.
placingAsset.setValidPlacement(true);
// The x and y Tiles to Highlight are the amount of Tiles that will be Highlighted in each Axis.
int xTilesToHighlight;
int yTilesToHighlight;
/* Since we don't know where to begin and end the Loops that will go through the soon-to-be Highlighted Tiles,
* we need to calculate them beforehand. */
int startingXLoop = 0;
int endingXLoop = 0;
int startingYLoop = 0;
int endingYLoop = 0;
// 1. First, we adjust the highlighting according to the facingDirection of the Asset
// Here, we apply the sizes in the right direction and set the axis corrections
if (placingAsset.getFacingDirection() == Entity.DOWN_RIGHT) {
xTilesToHighlight = placingAsset.getxSize();
yTilesToHighlight = placingAsset.getySize();
startingXLoop = 0;
endingXLoop = xTilesToHighlight;
startingYLoop = 0;
endingYLoop = yTilesToHighlight;
} else if(placingAsset.getFacingDirection() == Entity.DOWN_LEFT) {
xTilesToHighlight = -1 * placingAsset.getySize() + 1;
yTilesToHighlight = placingAsset.getxSize();
startingXLoop = xTilesToHighlight;
endingXLoop = 0;
startingYLoop = 0;
endingYLoop = yTilesToHighlight;
} else if(placingAsset.getFacingDirection() == Entity.UP_LEFT) {
xTilesToHighlight = -1 * placingAsset.getxSize() + 1;
yTilesToHighlight = -1 * placingAsset.getySize() + 1;
startingXLoop = xTilesToHighlight;
endingXLoop = 0;
startingYLoop = yTilesToHighlight;
endingYLoop = 0;
// Workaround to 1x1 objects. Without this, no tiles are highlighted
if(xTilesToHighlight == 0) {
startingXLoop = 0;
endingXLoop = 1;
}
if(yTilesToHighlight == 0) {
startingYLoop = 0;
endingYLoop = 1;
}
} else {//placingMarketAsset.getFacingDirection() == Entity.UP_RIGHT) {
xTilesToHighlight = placingAsset.getySize();
yTilesToHighlight = -1 * placingAsset.getxSize() + 1;
startingXLoop = 0;
endingXLoop = xTilesToHighlight;
startingYLoop = yTilesToHighlight;
endingYLoop = 0;
}
// 2. Here we prevent invalid highlighting (highlighting tiles that don't exist on the map (< 0 or > size)
if(endingXLoop + xTileAtMouse > getWidthInTiles()) {
endingXLoop -= ((xTileAtMouse + xTilesToHighlight) - getWidthInTiles());
placingAsset.setValidPlacement(false);
}
if(endingYLoop + yTileAtMouse > getHeightInTiles()) {
endingYLoop -= ((yTileAtMouse + yTilesToHighlight) - getHeightInTiles());
placingAsset.setValidPlacement(false);
}
if(xTileAtMouse + startingXLoop < 0) {
startingXLoop -= xTilesToHighlight + xTileAtMouse;
placingAsset.setValidPlacement(false);
}
if(yTileAtMouse + startingYLoop < 0) {
startingYLoop -= yTilesToHighlight + yTileAtMouse;
placingAsset.setValidPlacement(false);
}
// 3. We check if the Highlighted tiles are intersecting with other solid Entities on the map
// or if they're getting outside the playable area
// First on the x axis
for(int i = startingXLoop; i < endingXLoop; i++) {
if(isBlocked(xTileAtMouse + i, yTileAtMouse) || !isPlayable(xTileAtMouse + i, yTileAtMouse)) {
placingAsset.setValidPlacement(false);
}
}
// Then on the y axis
for(int j = startingYLoop; j < endingYLoop; j++) {
if(isBlocked(xTileAtMouse, yTileAtMouse + j) || !isPlayable(xTileAtMouse, yTileAtMouse + j)) {
placingAsset.setValidPlacement(false);
}
}
// Lastly in the intersection of the two
for(int i = startingXLoop; i < endingXLoop; i++) {
for(int j = startingYLoop; j < endingYLoop; j++) {
if(isBlocked(xTileAtMouse + i, yTileAtMouse + j) || !isPlayable(xTileAtMouse + i, yTileAtMouse + j)) {
placingAsset.setValidPlacement(false);
}
}
}
// 4. We loop through those tiles that need highlighting and highlight them
// First on the x axis
for(int i = startingXLoop; i < endingXLoop; i++) {
gameTiles[xTileAtMouse + i][yTileAtMouse].setHighlighted(true);
}
// Then on the y axis
for(int j = startingYLoop; j < endingYLoop; j++) {
gameTiles[xTileAtMouse][yTileAtMouse + j].setHighlighted(true);
}
// Lastly in the intersection of the two
for(int i = startingXLoop; i < endingXLoop; i++) {
for(int j = startingYLoop; j < endingYLoop; j++) {
gameTiles[xTileAtMouse + i][yTileAtMouse + j].setHighlighted(true);
}
}
// 5. In an special case, when the user is trying to place a Tv or a Console, mouse overing
// a Table should not result in an Invalid Placement
if(placingAsset instanceof Tv || placingAsset instanceof Console) {
// Check if the placement has been market as Invalid
if(!placingAsset.isValidPlacement()) {
// Finally check if the Object below the Mouse is a Table
for(Table t : tables) {
if(t.tilesGotMouseOvered(xTileAtMouse, yTileAtMouse)) {
placingAsset.setValidPlacement(true);
}
}
}
}
}
// Set the previous Tile x and y at Mouse
previousXTileAtMouse = xTileAtMouse;
previousYTileAtMouse = yTileAtMouse;
}
/**
* Buying a map area (can't buy the borders of the map)
* @throws SlickException
*/
public void buyTile(Business business) throws SlickException {
if (xTileAtMouse != 0 && yTileAtMouse != 0
&& xTileAtMouse != this.getWidth() -1 && yTileAtMouse != this.getHeight() -1
&& playable[xTileAtMouse][yTileAtMouse] == false) {
// Haz the money?
if (business.getMoney() >= business.getTilePrice()) {
business.makeBusiness(-business.getTilePrice(), Business.BUYING_MAP, true);
playable[xTileAtMouse][yTileAtMouse] = true;
updateMapLimits();
}
}
}
/**
* Renders each layer of the Map according to the Camera Offset
* @param container
* @param game
* @param g
* @throws SlickException
*/
public void render(GameContainer container, StateBasedGame game, Graphics g, float cameraSpeed, Asset placingAsset) throws SlickException {
// Floor
for (Floor f : floors) {
f.render(container, game, g);
}
// Renders the Tile layer
for(int i = 0; i < getWidth(); i++) {
for(int j = 0; j < getHeight(); j++) {
gameTiles[i][j].render(container, game, g, cameraSpeed, placingAsset);
}
}
// Renders the Line layer (blue lines around the Tiles)
// It is done this way so that the Polygon selection looks good in the Pixel Art.
super.render((int)xOffset, (int)yOffset, LINES);
}
/**
* When the borders of the map change, find out where we need to place walls and floor tiles
* @throws SlickException
*/
public void updateMapLimits() throws SlickException {
// Reset our lists
walls.clear();
floors.clear();
// Generate Walls
boolean isPreviousTilePlayable = false;
// First on Y
for (int tileX = 0; tileX < getWidth(); tileX++) {
for(int tileY = 0; tileY < getHeight(); tileY++) {
if (isPreviousTilePlayable == false && playable[tileX][tileY]) {
Wall w = new Wall(tileX, tileY, Entity.DOWN_LEFT);
this.snapToGrid(w);
walls.add(w);
} else if (isPreviousTilePlayable == true && playable[tileX][tileY] == false) {
Wall w = new Wall(tileX, tileY, Entity.UP_RIGHT);
this.snapToGrid(w);
walls.add(w);
}
isPreviousTilePlayable = playable[tileX][tileY];
}
}
// Then on X
for (int tileY = 0; tileY < getHeight(); tileY++) {
for(int tileX = 0; tileX < getWidth(); tileX++) {
if (isPreviousTilePlayable == false && playable[tileX][tileY]) {
Wall w = new Wall(tileX - 1, tileY, Entity.DOWN_RIGHT);
this.snapToGrid(w);
walls.add(w);
} else if (isPreviousTilePlayable == true && playable[tileX][tileY] == false) {
Wall w = new Wall(tileX, tileY, Entity.UP_LEFT);
this.snapToGrid(w);
walls.add(w);
}
isPreviousTilePlayable = playable[tileX][tileY];
// Place floor sprites
Floor f = new Floor(tileX, tileY, playable[tileX][tileY]);
this.snapToGrid(f);
floors.add(f);
}
}
// Unblock the new tiles
blocked[xTileAtMouse][yTileAtMouse] = false;
}
/**
* Places a Character on the Map
* @param entity
* @param xTile
* @param yTile
* @return
*/
public void placeObject(Character character, int xTile, int yTile) {
// Set the xTile and yTile of the Character on the Map
character.setXTile(xTile);
character.setYTile(yTile);
// Set the xPos and yPos of the Entity
snapToGrid(character);
}
/**
* Places an Asset on the Map
* @param asset
* @param xTile
* @param yTile
* @throws SlickException
*/
public void placeObject(Asset asset, ArrayList<Character> characters, int xTile, int yTile) throws SlickException {
// Set the xTile and yTile of the Asset on the Map
asset.setXTile(xTile);
asset.setYTile(yTile);
// Blocks the Tiles the Asset occupies
if(asset.blocksMap()) {
// The Tiles this Asset will block on the Map
int assetMapXTiles[] = new int[asset.getxSize() * asset.getySize()];
int assetMapYTiles[] = new int[asset.getxSize() * asset.getySize()];
int currentLoop = 0; // Count that will go through the two arrays above
// Block the Highlighted Tiles
for(int i = 0; i < getWidth(); i++) {
for(int j = 0; j < getHeight(); j++) {
if(gameTiles[i][j].isHighlighted()) {
// The Tile will be marked as blocked
assetMapXTiles[currentLoop] = i;
assetMapYTiles[currentLoop] = j;
// Increase the loop count
currentLoop++;
}
}
}
// The Asset object should know which Tiles it blocks on the Map
asset.setMapXTiles(assetMapXTiles);
asset.setMapYTiles(assetMapYTiles);
// Block those Tiles on the Map
for(int i = 0; i < asset.getxSize() * asset.getySize(); i++) {
block(asset.getMapXTiles()[i], asset.getMapYTiles()[i]);
}
// Move Characters away from there
this.moveCharactersAway(asset, characters);
}
// Set the Asset's usable Tiles. This is where the Characters will move to when using the Asset
// For a console, the Tiles around the chair are the usable ones. That means 6 Tiles
int usableXTiles[] = new int[1]; // Initialize
int usableYTiles[] = new int[1];
if(asset instanceof Table) {
// Create the arrays of usable tiles
usableXTiles = new int[4];
for(int i = 0; i < usableXTiles.length; i++) usableXTiles[i] = -1;
usableYTiles = new int[4];
for(int i = 0; i < usableYTiles.length; i++) usableYTiles[i] = -1;
if(asset.getFacingDirection() == Entity.DOWN_RIGHT) {
// Available Tiles directly in front of the Asset
if(asset.getXTile() + (asset.getxSize()) < this.getWidth()) {
usableXTiles[0] = asset.getXTile() + asset.getxSize();
usableYTiles[0] = asset.getYTile();
usableXTiles[1] = asset.getXTile() + asset.getxSize();
usableYTiles[1] = asset.getYTile() + 1;
}
// Available Tiles on the left of the Asset (x+)
if(asset.getYTile() + asset.getySize() < this.getWidth()) {
usableXTiles[2] = asset.getXTile() + asset.getxSize() - 1;
usableYTiles[2] = asset.getYTile() + asset.getySize();
}
// Available Tiles on the right of the Asset (x-);
if(asset.getYTile() > 0) {
usableXTiles[3] = asset.getXTile() + asset.getxSize() - 1;
usableYTiles[3] = asset.getYTile() - 1;
}
} else if(asset.getFacingDirection() == Entity.DOWN_LEFT) {
// Available Tiles directly in front of the Asset
if(asset.getYTile() + asset.getxSize() < this.getHeight()) {
usableXTiles[0] = asset.getXTile();
usableYTiles[0] = asset.getYTile() + asset.getxSize();
usableXTiles[1] = asset.getXTile() - 1;
usableYTiles[1] = asset.getYTile() + asset.getxSize();
}
// Available Tiles on the left of the Asset (y-)
if(asset.getXTile() - asset.getySize() >= 0) {
usableXTiles[2] = asset.getXTile() - asset.getySize();
usableYTiles[2] = asset.getYTile() + asset.getxSize() - 1;
}
// Available Tiles on the right of the Asset (y+);
if(asset.getXTile() + 1 < this.getWidth()) {
usableXTiles[3] = asset.getXTile() + 1;
usableYTiles[3] = asset.getYTile() + asset.getxSize() - 1;
}
} else if(asset.getFacingDirection() == Entity.UP_LEFT) {
// Available Tiles directly in front of the Asset
if(asset.getXTile() - asset.getxSize() >= 0) {
usableXTiles[0] = asset.getXTile() - asset.getxSize();
usableYTiles[0] = asset.getYTile();
usableXTiles[1] = asset.getXTile() - asset.getxSize();
usableYTiles[1] = asset.getYTile() - 1;
}
// Available Tiles on the left of the Asset (y+)
if(asset.getYTile() + 1 < this.getHeight()) {
usableXTiles[2] = asset.getXTile() - asset.getxSize() + 1;
usableYTiles[2] = asset.getYTile() + 1;
}
// Available Tiles on the right of the Asset (y-);
if(asset.getYTile() - asset.getySize() >= 0) {
usableXTiles[3] = asset.getXTile() - asset.getxSize() + 1;
usableYTiles[3] = asset.getYTile() - asset.getySize();
}
} else { // if(asset.getFacingDirection() == Entity.UP_RIGHT) {
// Available Tiles directly in front of the Asset
if(asset.getYTile() - asset.getxSize() >= 0) {
usableXTiles[0] = asset.getXTile();
usableYTiles[0] = asset.getYTile() - asset.getxSize();
usableXTiles[1] = asset.getXTile() + 1;
usableYTiles[1] = asset.getYTile() - asset.getxSize();
}
// Available Tiles on the left of the Asset (y-)
if(asset.getXTile() - 1 >= 0) {
usableXTiles[2] = asset.getXTile() + asset.getySize();
usableYTiles[2] = asset.getYTile() - asset.getxSize() + 1;
}
// Available Tiles on the right of the Asset (y+);
if(asset.getXTile() + asset.getySize() < this.getWidth()) {
usableXTiles[3] = asset.getXTile() - 1;
usableYTiles[3] = asset.getYTile() - asset.getxSize() + 1;
}
}
} else {
// For all other Assets, it's the Tiles directly in front of it
// Create the arrays of usable tiles
usableXTiles = new int[asset.getySize()];
for(int i = 0; i < usableXTiles.length; i++) usableXTiles[i] = -1;
usableYTiles = new int[asset.getySize()];
for(int i = 0; i < usableYTiles.length; i++) usableYTiles[i] = -1;
// Every Tile in front of the Asset becomes usable, doesn't matter its size.
if(asset.getFacingDirection() == Entity.DOWN_RIGHT) {
// Check if the position is ok
if(asset.getXTile() + asset.getxSize() < this.getWidth()) {
// For each Y in that X...
for(int i = 0; i < asset.getySize(); i++) {
usableXTiles[i] = asset.getXTile() + asset.getxSize();
usableYTiles[i] = asset.getYTile() + i;
}
}
} else if(asset.getFacingDirection() == Entity.DOWN_LEFT) {
// Check if the position is ok
if(asset.getYTile() + asset.getxSize() < this.getHeight()) {
// For each Y in that X...
for(int i = 0; i < asset.getySize(); i++) {
usableXTiles[i] = asset.getXTile() - i;
usableYTiles[i] = asset.getYTile() + asset.getxSize();
}
}
} else if(asset.getFacingDirection() == Entity.UP_LEFT) {
// Check if the position is ok
if(asset.getXTile() - asset.getxSize() >= 0) {
// For each Y in that X...
for(int i = 0; i < asset.getySize(); i++) {
usableXTiles[i] = asset.getXTile() - asset.getxSize();
usableYTiles[i] = asset.getYTile() - i;
}
}
} else { //if(asset.getFacingDirection() == Entity.UP_RIGHT)
// Check if the position is ok
if(asset.getYTile() - asset.getxSize() >= 0) {
// For each Y in that X...
for(int i = 0; i < asset.getySize(); i++) {
usableXTiles[i] = asset.getXTile() + i;
usableYTiles[i] = asset.getYTile() - asset.getxSize();
}
}
}
}
// After calculating, set their usable Tiles
asset.setUsableXTiles(usableXTiles);
asset.setUsableYTiles(usableYTiles);
// Set the xPos and yPos of the Asset
snapToGrid(asset);
// Set not being on a Table
asset.setOnTable(false);
// Updates the Depth of the Asset on the Map
asset.updateDepth();
}
/**
* Check if there were any Characters in the blocked Tiles so we move them out
* @param asset
* @param characters
* @throws SlickException
*/
public void moveCharactersAway(Asset asset, ArrayList<Character> characters) throws SlickException {
for(int i = 0; i < asset.getxSize() * asset.getySize(); i++) {
// Loop through Characters
for(Character c : characters) {
// Check if the Character position intersects with the Asset position
if(c.getXTile() == asset.getMapXTiles()[i] && c.getYTile() == asset.getMapYTiles()[i]) {
// Ops. Found a Character there! Let's get that fucker out.
int nextFreeXTile = -1;
int nextFreeYTile = -1;
// Let's find the next free tile, looking in all 4 directions
if(asset.getMapXTiles()[i] + 1 < getWidth()) {
if(!isBlocked(asset.getMapXTiles()[i] + 1, asset.getMapYTiles()[i])) { // DOWN RIGHT
nextFreeXTile = asset.getMapXTiles()[i] + 1;
nextFreeYTile = asset.getMapYTiles()[i];
}
}
if(asset.getMapXTiles()[i] - 1 >= 0) {
if(!isBlocked(asset.getMapXTiles()[i] - 1, asset.getMapYTiles()[i])) { // UP LEFT
nextFreeXTile = asset.getMapXTiles()[i] - 1;
nextFreeYTile = asset.getMapYTiles()[i];
}
}
if(asset.getMapYTiles()[i] + 1 < getHeight()) {
if(!isBlocked(asset.getMapXTiles()[i], asset.getMapYTiles()[i] + 1)) { // DOWN RIGHT
nextFreeXTile = asset.getMapXTiles()[i];
nextFreeYTile = asset.getMapYTiles()[i] + 1;
}
}
if(asset.getMapYTiles()[i] - 1 >= 0) {
if(!isBlocked(asset.getMapXTiles()[i], asset.getMapYTiles()[i] - 1)) { // UP RIGHT
nextFreeXTile = asset.getMapXTiles()[i];
nextFreeYTile = asset.getMapYTiles()[i] - 1;
}
}
// We should have both Tiles now
// If we don't, then place the Character back at the spawning location.
if(nextFreeXTile == -1 || nextFreeYTile == -1) {
placeObject(c, spawnPoint.x, spawnPoint.y);
} else {
// Otherwise, place the Character in the found location
placeObject(c, nextFreeXTile, nextFreeYTile);
}
// Last but not least, we update its position and stop its movement
c.stopMoving(this);
c.setPath(null);
c.setXPos(c.getOriginalXPos());
c.setYPos(c.getOriginalYPos());
c.setState(Character.IDLE);
}
}
}
}
/**
* If the player was moving an Asset and hit right click, we put the Asset back in its original position
* @param asset
* @throws SlickException
*/
public void releaseMovingObject(Asset asset, ArrayList<Character> characters) throws SlickException {
// Block the Tiles the Asset used to block
for(int i = 0; i < asset.getxSize() * asset.getySize(); i++) {
block(asset.getMapXTiles()[i], asset.getMapYTiles()[i]);
}
// Get Characters away from those tiles
this.moveCharactersAway(asset, characters);
}
/**
* Removes an Asset from the Map, freeing up the Tiles it occupies
* @param asset
*/
public void removeObject(Asset asset) {
// Unblocks the Tiles this asset is currently blocking
if(asset.blocksMap()) {
for(int i = 0; i < asset.getxSize() * asset.getySize(); i++) {
unblock(asset.getMapXTiles()[i], asset.getMapYTiles()[i]);
}
}
}
/**
* Updates the position of a Character on the Map
* @param character
*/
public void snapToGrid(Character character) {
// x and y Offsets
float xSpriteOffset = 0f;
float ySpriteOffset = 0f;
// Characters have an specific placement so their feet fit the middle of the Tile
xSpriteOffset = -1f * (character.getSpriteWidth() / 2f);
ySpriteOffset = -1f * (character.getSpriteHeight() + (getTileHeight() / 3f));
// Set the x and y Pos
character.setXPos((getTileWidth() / 2f * character.getXTile()) - (getTileWidth() / 2f * character.getYTile()) + (getTileWidth() / 2f) + xSpriteOffset);
character.setYPos((getTileHeight() / 2f * character.getXTile()) + (getTileHeight() / 2f * character.getYTile()) + (getTileHeight()) + ySpriteOffset);
}
/**
* Fixes the position of a Wall on the map
* @param character
*/
public void snapToGrid(Wall wall) {
float xSpriteOffset = 0f;
float ySpriteOffset = 0f;
// x and y Offsets
if (wall.getFacingDirection() == Entity.DOWN_LEFT) {
xSpriteOffset = 0f;
ySpriteOffset = -35f;
} else if (wall.getFacingDirection() == Entity.DOWN_RIGHT) {
xSpriteOffset = -4f;
ySpriteOffset = -27f;
} else if (wall.getFacingDirection() == Entity.UP_LEFT) {
xSpriteOffset = -16f;
ySpriteOffset = -33f;
} else {
xSpriteOffset = -4f;
ySpriteOffset = -33f;
}
// Set the x and y Pos
wall.setXPos((getTileWidth() / 2f * wall.getXTile()) - (getTileWidth() / 2f * wall.getYTile()) + (getTileWidth() / 2f) + xSpriteOffset);
wall.setYPos((getTileHeight() / 2f * wall.getXTile()) + (getTileHeight() / 2f * wall.getYTile()) + (getTileHeight()) + ySpriteOffset);
}
/**
* Fixes the position of a Floor tile on the map
* @param character
*/
public void snapToGrid(Floor floor) {
float xSpriteOffset = -16f;
float ySpriteOffset = -16f;
// Set the x and y Pos
floor.setXPos((getTileWidth() / 2f * floor.getXTile()) - (getTileWidth() / 2f * floor.getYTile()) + (getTileWidth() / 2f) + xSpriteOffset);
floor.setYPos((getTileHeight() / 2f * floor.getXTile()) + (getTileHeight() / 2f * floor.getYTile()) + (getTileHeight()) + ySpriteOffset);
}
/**
* Updates the position of an Asset on the Map
*
* /----------------------------\
* | Worst code I've ever written |
* \----------------------------/
*
* @param asset
*/
public void snapToGrid(Asset asset) {
// x and y Offsets
float xSpriteOffset = 0f;
float ySpriteOffset = 0f;
// Asset placement adjust, according to the facingDirection
if(asset.getFacingDirection() == Entity.DOWN_RIGHT) {
if(asset instanceof Shelf) { xSpriteOffset = -1f * (getTileWidth() * 0.5f);}
else if(asset instanceof Tv) { xSpriteOffset = -1f * getTileWidth() * 0.25f - 2f;}
else if(asset instanceof Console) { xSpriteOffset = -1f * getTileWidth() * 0.25f - 3f;}
else if(asset instanceof Table) { xSpriteOffset = -1f * (getTileWidth());}
else if(asset instanceof Misc) { xSpriteOffset = -1f * (getTileWidth() * 0.5f - 5f);}
if(asset instanceof Shelf) { ySpriteOffset = -1f * (getTileHeight() * 2.75f);}
else if(asset instanceof Tv) { ySpriteOffset = -1f * getTileHeight() * 1.25f - 3f;}
else if(asset instanceof Console) { ySpriteOffset = -1f * getTileHeight();}
else if(asset instanceof Table) { ySpriteOffset = -1f * (getTileHeight()) * 1.25f;}
else if(asset instanceof Misc) { ySpriteOffset = -1f * (getTileHeight() * 2.5f + 2f);}
} else if (asset.getFacingDirection() == Entity.DOWN_LEFT) {
if(asset instanceof Shelf) { xSpriteOffset = -1f * (getTileWidth() * 0.5f);}
else if(asset instanceof Tv) { xSpriteOffset = -1f * (getTileWidth() * 0.5f - 2f);}
else if(asset instanceof Console) { xSpriteOffset = -1f * getTileWidth() * 0.25f - 4f;}
else if(asset instanceof Table) { xSpriteOffset = -1f * (getTileWidth());}
else if(asset instanceof Misc) { xSpriteOffset = -1f * (getTileWidth() * 0.5f - 5f);}
if(asset instanceof Shelf) { ySpriteOffset = -1f * (getTileHeight() * 2.75f);}
else if(asset instanceof Tv) { ySpriteOffset = -1f * (getTileHeight() * 1.5f - 1f);}
else if(asset instanceof Console) { ySpriteOffset = -1f * getTileHeight();}
else if(asset instanceof Table) { ySpriteOffset = -1f * (getTileHeight() * 1.75f);}
else if(asset instanceof Misc) { ySpriteOffset = -1f * (getTileHeight() * 2.5f + 2f);}
} else if (asset.getFacingDirection() == Entity.UP_LEFT) {
if(asset instanceof Shelf) { xSpriteOffset = -1f * (getTileWidth() / 2f);}
else if(asset instanceof Tv) { xSpriteOffset = -1f * getTileWidth() * 0.25f;}
else if(asset instanceof Console) { xSpriteOffset = -1f * getTileWidth() / 2.25f;}
else if(asset instanceof Table) { xSpriteOffset = -1f * (getTileWidth() / 2f);}
else if(asset instanceof Misc) { xSpriteOffset = -1f * (getTileWidth() * 0.5f - 5f);}
if(asset instanceof Shelf) { ySpriteOffset = -1f * (getTileHeight() * 2.75f);}
else if(asset instanceof Tv) { ySpriteOffset = -1f * getTileHeight() * 1.5f;}
else if(asset instanceof Console) { ySpriteOffset = -1f * getTileHeight();}
else if(asset instanceof Table) { ySpriteOffset = -1f * (getTileHeight() * 1.75f);}
else if(asset instanceof Misc) { ySpriteOffset = -1f * (getTileHeight() * 2.5f + 2f);}
} else { //asset.getFacingDirection() == Entity.UP_RIGHT
if(asset instanceof Shelf) { xSpriteOffset = -1f * (getTileWidth() / 2f);}
else if(asset instanceof Tv) { xSpriteOffset = -1f * getTileWidth() * 0.25f - 3f;}
else if(asset instanceof Console) { xSpriteOffset = -1f * getTileWidth() / 2.5f;}
else if(asset instanceof Table) { xSpriteOffset = -1f * (getTileWidth() / 2f);}
else if(asset instanceof Misc) { xSpriteOffset = -1f * (getTileWidth() * 0.5f - 5f);}
if(asset instanceof Shelf) { ySpriteOffset = -1f * (getTileHeight() * 2.75f);}
else if(asset instanceof Tv) { ySpriteOffset = -1f * getTileHeight() * 1.5f;}
else if(asset instanceof Console) { ySpriteOffset = -1f * getTileHeight();}
else if(asset instanceof Table) { ySpriteOffset = -1f * (getTileHeight()* 1.25f);}
else if(asset instanceof Misc) { ySpriteOffset = -1f * (getTileHeight() * 2.5f + 2f);}
}
// Set the x and y Sprite Offset
asset.setxSpriteOffset(xSpriteOffset);
asset.setySpriteOffset(ySpriteOffset);
// Set the x and y Pos
asset.setXPos((getTileWidth() / 2 * asset.getXTile()) - (getTileWidth() / 2 * asset.getYTile()) + (getTileWidth() / 2));
asset.setYPos((getTileHeight() / 2 * asset.getXTile()) + (getTileHeight() / 2 * asset.getYTile()) + (getTileHeight()));
}
/**
* Unhighlights all Tiles
*/
public void unhighlightAll() {
for(int i = 0; i < getWidth(); i++) {
for(int j = 0; j < getHeight(); j++) {
gameTiles[i][j].setHighlighted(false);
}
}
}
/**
* Returns a list of Walls and Floors
*
* @return
*/
public ArrayList<Terrain> getTerrain() {
ArrayList<Terrain> terrainBlocks = new ArrayList<Terrain>();
terrainBlocks.addAll(walls);
terrainBlocks.addAll(floors);
return terrainBlocks;
}
// isBlocked, Block and Unblock
public boolean isBlocked(int x, int y) {return blocked[x][y];}
public void block(int x, int y) {blocked[x][y] = true;}
public void unblock(int x, int y) {blocked[x][y] = false;}
// Is playable
public boolean isPlayable(int x, int y) {return playable[x][y];}
/**
* Returns a list of playable map tiles
* @return
*/
public int getAmountOfPlayableTiles() {
int playableTiles = 0;
for (int i = 0; i < playable.length; i++) {
for (int j = 0; j < playable[i].length; j++) {
if (playable[i][j]) {
playableTiles++;
}
}
}
return playableTiles;
}
@Override
public void pathFinderVisited(int x, int y) {
// TODO Auto-generated method stub
}
@Override
public boolean blocked(PathFindingContext context, int tx, int ty) {
return blocked[tx][ty];
}
@Override
public float getCost(PathFindingContext context, int tx, int ty) {
return 0;
}
public int getXTileAtMouse() {return xTileAtMouse;}
public int getYTileAtMouse() {return yTileAtMouse;}
public AStarPathFinder getPathFinder() {return pathFinder;}
@Override
public int getHeightInTiles() {
return getHeight();
}
@Override
public int getWidthInTiles() {
return getWidth();
}
public float getxOffset() {
return xOffset;
}
public void setxOffset(float xOffset) {
this.xOffset = xOffset;
}
public float getyOffset() {
return yOffset;
}
public void setyOffset(float yOffset) {
this.yOffset = yOffset;
}
public int getTileWidth() {
return tileWidth;
}
public int getTileHeight() {
return tileHeight;
}
public Tile getSpawnPoint() {
return spawnPoint;
}
public void setSpawnPoint(Tile spawnPoint) {
this.spawnPoint = spawnPoint;
}
public ArrayList<Wall> getWalls() {
return walls;
}
public void setWalls(ArrayList<Wall> walls) {
this.walls = walls;
}
public ArrayList<Floor> getFloors() {
return floors;
}
public void setFloors(ArrayList<Floor> floors) {
this.floors = floors;
}
}