package pelletQuest.map;
import pelletQuest.resources.AudioManager;
import pelletQuest.resources.Translator;
import java.util.*;
import pelletQuest.entities.*;
import org.newdawn.slick.*;
import org.newdawn.slick.geom.Rectangle;
import org.newdawn.slick.geom.Vector2f;
import org.newdawn.slick.util.xml.*;
public class GameMap {
protected String url;
protected String mapName;
protected Tile[][] mapData;
protected ArrayList<Entity> entities = new ArrayList<Entity>();
protected Zone zone;
protected String spritesheet;
protected String miniSpritesheet;
protected String pixelSpritesheet;
protected int worldX;
protected int worldY;
protected int worldZ;
protected String soundtrack;
protected GameMap () {}
public GameMap (String url, String mapName, Tile[][] mapData, Zone zone, String spritesheet, String miniSpritesheet, String pixelSpritesheet, int worldX, int worldY, int worldZ, String soundtrack) {
this.url = url;
this.mapName = mapName;
this.mapData = mapData;
this.zone = zone;
this.spritesheet = spritesheet;
this.miniSpritesheet = miniSpritesheet;
this.pixelSpritesheet = pixelSpritesheet;
this.worldX = worldX;
this.worldY = worldY;
this.worldZ = worldZ;
this.soundtrack = soundtrack;
}
public GameMap (String filepath, Zone zone) throws SlickException {
this.zone = zone;
XMLParser parser = new XMLParser();
XMLElement root = parser.parse(filepath);
url = filepath;
mapName = Translator.convert( root.getAttribute("name", "???") );
spritesheet = root.getAttribute("spritesheet");
miniSpritesheet = root.getAttribute("miniSpritesheet");
pixelSpritesheet = root.getAttribute("pixelSpritesheet");
worldX = root.getIntAttribute("worldX");
worldY = root.getIntAttribute("worldY");
worldZ = root.getIntAttribute("worldZ");
soundtrack = root.getAttribute("soundtrack");
mapData = new Tile[18][27];
String rawData = root.getContent();
rawData = rawData.replaceAll("\\s", "");
Scanner scan = new Scanner(rawData);
scan.useDelimiter(";;");
for (int i=0; i<(27*18); i++) {
mapData[i/27][i%27] = new Tile(scan.next());
}
XMLElementList spawns = root.getChildrenByName("entities").get(0).getChildren();
for (int i=0; i<spawns.size(); i++) {
if (spawns.get(i).getName().equals("spawn")) {
spawn(spawns.get(i), spawns.get(i).getIntAttribute("x"), spawns.get(i).getIntAttribute("y"), this, filepath);
} else if (spawns.get(i).getName().equals("flood")) {
floodSpawn(spawns.get(i), filepath);
}
}
}
public void floodSpawn (XMLElement tag, String filepath) throws SlickException {
if (!canFlood(tag, tag.getIntAttribute("x"), tag.getIntAttribute("y"))) {
return;
}
XMLElementList spawns = tag.getChildrenByName("spawn");
boolean[][] floodmap = new boolean[mapData.length][mapData[0].length];
for (int i=0; i<spawns.size(); i++) {
spawn(spawns.get(i), tag.getIntAttribute("x"), tag.getIntAttribute("y"), this, filepath);
}
floodmap[tag.getIntAttribute("y")][tag.getIntAttribute("x")] = true;
boolean hasChanged = true;
while (hasChanged) {
hasChanged = false;
for (int row=0; row < mapData.length; row++) {
for (int column=0; column < mapData[0].length; column++) {
if (!floodmap[row][column]) {
if ((row < mapData.length-1 && floodmap[row+1][column]) || (row > 0 && floodmap[row-1][column]) || (column < mapData[0].length-1 && floodmap[row][column+1]) || (column > 0 && floodmap[row][column-1])) {
if (column < mapData[0].length-1 && row < mapData.length-1 && column > 0 && row > 0) {
if (canFlood(tag, column, row)) {
if (canSpawn(tag, column, row)) {
for (int i=0; i<spawns.size(); i++) {
spawn(spawns.get(i), column, row, this, filepath);
}
}
floodmap[row][column] = true;
hasChanged = true;
}
}
}
}
}
}
}
}
public static void spawn (XMLElement tag, int x, int y, GameMap m, String filepath) throws SlickException {
int multiplyBy = 16;
if (tag.getBooleanAttribute("absolutePosition", false)) {
multiplyBy = 1;
}
Rectangle boundingBox = new Rectangle((x*multiplyBy)+tag.getIntAttribute("offsetX", 0), (y*multiplyBy)+tag.getIntAttribute("offsetY", 0), tag.getIntAttribute("width", 15), tag.getIntAttribute("height", 15));
EntityPhase[] phases = new EntityPhase[tag.getChildrenByName("phase").size()];
for (int h=0; h < phases.length; h++) {
phases[h] = buildPhase(tag.getChildrenByName("phase").get(h));
}
new SpawnedEntity
(
tag.getAttribute("name"),
m,
boundingBox,
phases,
tag.getBooleanAttribute("resets", false)
);
}
public static EntityPhase buildPhase (XMLElement phaseTag) throws SlickXMLException {
String[] onUpdate = new String[phaseTag.getChildrenByName("onUpdate").size()];
for (int i=0; i < onUpdate.length; i++) {
onUpdate[i] = phaseTag.getChildrenByName("onUpdate").get(i).getContent();
}
String[] onCollide = new String[phaseTag.getChildrenByName("onCollide").size()];
for (int i=0; i < onCollide.length; i++) {
onCollide[i] = phaseTag.getChildrenByName("onCollide").get(i).getContent();
}
String[] onEnter = new String[phaseTag.getChildrenByName("onEnter").size()];
for (int i=0; i < onEnter.length; i++) {
onEnter[i] = phaseTag.getChildrenByName("onEnter").get(i).getContent();
}
String[] onHurt = new String[phaseTag.getChildrenByName("onHurt").size()];
for (int i=0; i < onHurt.length; i++) {
onHurt[i] = phaseTag.getChildrenByName("onHurt").get(i).getContent();
}
String[] walkableTerrains = new String[phaseTag.getChildrenByName("canWalkOn").size()];
for (int i=0; i < walkableTerrains.length; i++) {
walkableTerrains[i] = phaseTag.getChildrenByName("canWalkOn").get(i).getAttribute("terrain");
}
return new EntityPhase
(
phaseTag.getAttribute("sprite", null),
phaseTag.getAttribute("behavior", null),
onCollide,
onUpdate,
onEnter,
onHurt,
walkableTerrains,
new Vector2f(phaseTag.getIntAttribute("drawFromX", 0),phaseTag.getIntAttribute("drawFromY", 0)),
phaseTag.getBooleanAttribute("isSolid", false),
phaseTag.getIntAttribute("layer", 1),
phaseTag.getIntAttribute("moveSpeed", 25),
phaseTag.getIntAttribute("animSpeed", phaseTag.getIntAttribute("moveSpeed", 25)*5),
phaseTag.getIntAttribute("damage", 0),
phaseTag.getDoubleAttribute("direction", 0),
phaseTag.getIntAttribute("duration", -1),
phaseTag.getBooleanAttribute("canTeleport", false),
phaseTag.getBooleanAttribute("collidesWithSolids", true),
phaseTag.getBooleanAttribute("canMoveOff", false),
phaseTag.getBooleanAttribute("canMoveThrough", false)
);
}
protected boolean canFlood (XMLElement tag, int x, int y) throws SlickException {
boolean result = true;
if (!tag.getAttribute("terrain").startsWith(mapData[y][x].getTerrain())) {
return false;
}
for (int i=0; i < tag.getChildrenByName("edge").size(); i++) {
if (x == tag.getChildrenByName("edge").get(i).getIntAttribute("x") && y == tag.getChildrenByName("edge").get(i).getIntAttribute("y")) {
return false;
}
}
return result;
}
protected boolean canSpawn (XMLElement tag, int x, int y) throws SlickException {
for (int i=0; i < tag.getChildrenByName("skip").size(); i++) {
if (x == tag.getChildrenByName("skip").get(i).getIntAttribute("x") && y == tag.getChildrenByName("skip").get(i).getIntAttribute("y")) {
return false;
}
}
return true;
}
public static ArrayList<Entity> sortByPosition (ArrayList<Entity> ents) {
ArrayList<Entity> temp = new ArrayList<Entity>();
while (ents.size() > 0) {
int leastIndex = 0;
float least = ents.get(0).getBox().getCenterY();
for (int i=1; i<ents.size(); i++) {
float newValue = ents.get(i).getBox().getCenterY();
if (i != leastIndex && newValue < least) {
leastIndex = i;
least = newValue;
}
}
temp.add(ents.remove(leastIndex));
}
return temp;
}
public void renderMinimap (Graphics g, int x, int y) {
for (int row=1; row < mapData.length-1; row++) {
for (int column=1; column < mapData[row].length-1; column++) {
mapData[row][column].draw(miniSpritesheet, x+(column*2), y+(row*2));
}
}
}
public void renderPixelmap (Graphics g, int x, int y) {
for (int row=1; row < mapData.length-1; row++) {
for (int column=1; column < mapData[row].length-1; column++) {
mapData[row][column].draw(pixelSpritesheet, x+(column*1), y+(row*1));
}
}
}
public void render (Graphics g, int x, int y, boolean drawSpeech) {
for (int row=1; row < mapData.length-1; row++) {
for (int column=1; column < mapData[row].length-1; column++) {
mapData[row][column].draw(spritesheet, x+(column*16), y+(row*16));
}
}
for (int layer=0; layer < 4; layer++) {
if (layer == 2) { //Do a special sort on layer2 entities.
ArrayList<Entity> layer2s = new ArrayList<Entity>();
for (Entity e : entities) {
if (e.getLayer() == 2) {
layer2s.add(e);
}
}
layer2s = sortByPosition(layer2s);
for (Entity e : layer2s) {
e.render(g, x, y);
}
} else {
for (int row=1; row < mapData.length-1; row++) {
for (Entity e : entities) {
if (e.getLayer() == layer) {
if ((int)(e.getBox().getCenterY()/16) == row && e.getMap().equals(this)) {
e.render(g, x, y);
}
}
}
}
}
}
if (drawSpeech) {
for (Entity e : entities) {
e.renderVoice(g, x, y);
}
}
}
public void addEntity (Entity e) {
entities.add(e);
}
public void removeEntity (Entity e) {
for (int i=0; i<entities.size(); i++) {
if (entities.get(i).equals(e)) {
entities.remove(i);
break;
}
}
}
public ArrayList<Entity> getEntities () {
return entities;
}
public ArrayList<Entity> getUpdatableEntities () {
ArrayList<Entity> result = new ArrayList<Entity>();
for (Entity e : entities) {
if (e.getName() != "player") {
result.add(e);
}
}
return result;
}
public boolean[][] getPassableMap (String[] passableTerrains) {
boolean[][] walkmap = new boolean[mapData.length][mapData[0].length];
for (int row=0; row < mapData.length; row++) {
for (int column=0; column < mapData[row].length; column++) {
for (int i=0; i < passableTerrains.length; i++) {
walkmap[row][column] = (passableTerrains[i].startsWith(mapData[row][column].getTerrain())) || walkmap[row][column];
}
}
}
return walkmap;
}
/*
public int getPelletsRemaining() {
int numberOfPellets = 0;
for (Entity e : entities) {
if (e.getName().equalsIgnoreCase("pellet")) {
numberOfPellets++;
}
}
return numberOfPellets;
}
*/
public String getName() {
return mapName;
}
public int getHeight() {
return mapData.length;
}
public int getWidth() {
return mapData[0].length;
}
/*
public String getTile (int x, int y) {
return mapData[y][x].getTerrain();
}
*/
public String getURL() {
return url;
}
public void update(int delta) {
for (Tile[] a : mapData) {
for (Tile b : a) {
b.update(delta);
}
}
}
public void enter() {
AudioManager.self.setSoundtrack(soundtrack);
for (Entity e : entities) {
e.onEnterMap();
}
}
public void leave() {
for (Entity e : entities) {
e.onLeaveMap();
}
}
public Zone getZone() {
if (zone != null) {
return zone;
} else {
String[] temp = { url };
return new Zone(temp);
}
}
public int getWorldX() {
return worldX;
}
public int getWorldY() {
return worldY;
}
public int getWorldZ() {
return worldZ;
}
public String getSoundtrack() {
return soundtrack;
}
}