package domain;
import static core.Script.*;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.net.MalformedURLException;
import java.net.URL;
import core.Script;
import persist.ExtendedDataInputStream;
import persist.ExtendedDataOutputStream;
import domain.Entity;
public class MapVerge extends MapAbstract implements Map {
// .map format: https://github.com/Bananattack/v3tiled/wiki/.map-file
public static final String MAP_SIGNATURE = "V3MAP";
public static final int MAP_VERSION = 2;
private String filename = "";
private String mapname = "dummy";
String vspname = "";
private String musicname= "";
private String startupscript = "";
Layer[] layers;
byte[] obsLayer;
int[] zoneLayer; // width * height, Unsigned shorts!
Zone[] zones;
Entity[] entities;
public String toString() {
return "Mapname: " + filename + "; vspFile:" + vspname + "; music:"
+ musicname + "; render:" + renderstring + "; startEvent: "
+ startupscript + "; start:" + startX + "," + startY;
}
public MapVerge(String strFilename) {
this(Script.load(strFilename), strFilename);
}
public MapVerge(URL url, String strFilename) {
try {
if(url==null)
throw new IOException();
this.filename = strFilename; // url.getFile().substring( url.getFile().lastIndexOf('/')+1);
this.load(url.openStream());
//FileInputStream fis = new FileInputStream(path + "\\" + filename);
//this.load(fis);
// Load the vsp (map URL minus the map file plus the vsp file)
URL vspUrl = new URL(url.toString().substring(0, url.toString().lastIndexOf('/')+1) + this.vspname);
System.out.println(vspUrl);
this.tileset = new Vsp(vspUrl);
//this.tileset = new Vsp(Script.load(this.vspname));
// Diassociated with loading the map
startMap();
} catch (IOException ioe) {
System.err.println("MAP::IOException (" + filename + "), url = " + url);
}
}
public MapVerge(URL mapUrl, URL vspUrl) {
try {
this.load(mapUrl.openStream());
} catch (IOException e) {
System.err.println("MAP::IOException (" + filename + "), mapurl = " + mapUrl);
}
this.tileset = new Vsp(vspUrl);
}
/**
* Loads a Map from an InputStream
*
*/
private void load(InputStream is) {
try {
ExtendedDataInputStream f = new ExtendedDataInputStream(is);
// Begin to read
String mapSignature = f.readFixedString(6);
if (!mapSignature.equals(MAP_SIGNATURE)) {
throw new IOException("Map doesn't contain V3MAP signature: " + mapSignature);
}
int mapVersion = f.readSignedIntegerLittleEndian();
int vcOffset = f.readSignedIntegerLittleEndian();
//System.out.println("Map version:" + mapVersion + "; Vcoffset: " + vcOffset);
// Map information
this.mapname = f.readFixedString(256);
this.vspname = f.readFixedString(256);
this.musicname = f.readFixedString(256);
this.renderstring = f.readFixedString(256);
this.startupscript = f.readFixedString(256);
this.startX = f.readUnsignedShortLittleEndian();
this.startY = f.readUnsignedShortLittleEndian();
int numLayers = f.readSignedIntegerLittleEndian(); // layers.length
this.layers = new Layer[numLayers];
for (int i = 0; i < numLayers; i++) {
Layer l = new Layer();
l.name = f.readFixedString(256);
l.parallax_x = f.readDoubleLittleEndian();
l.parallax_y = f.readDoubleLittleEndian();
l.width = f.readUnsignedShortLittleEndian();
l.height = f.readUnsignedShortLittleEndian();
l.lucent = f.readUnsignedByte();
l.tiledata = f.readCompressedUnsignedShorts();
this.layers[i] = l;
}
// Read compressed (oLayer)
this.obsLayer = f.readCompressedBytes();
// Read compressed (zLayer)
this.zoneLayer = f.readCompressedUnsignedShorts();
int numZones = f.readSignedIntegerLittleEndian(); // zones.length
this.zones = new Zone[numZones];
//System.out.println("numZones = " + numZones);
for (int i = 0; i < numZones; i++) {
Zone z = new Zone();
z.name = f.readFixedString(256);
z.script = f.readFixedString(256);
z.percent = f.readUnsignedByte();
z.delay = f.readUnsignedByte();
z.method = f.readUnsignedByte();
this.zones[i] = z;
}
int numEntities = f.readSignedIntegerLittleEndian(); // entities.length
this.entities = new Entity[numEntities];
//System.out.println("numEntities = " + numEntities);
for (int i = 0; i < numEntities; i++) {
//Entity e = new Entity();
int x = f.readUnsignedShortLittleEndian();
int y = f.readUnsignedShortLittleEndian();
Entity e = new Entity(x*16, y*16, null);
e.face = f.readByte();
e.obstructable = f.readByte() == 0 ? false : true;
e.obstruction = f.readByte() == 0 ? false : true;
e.autoface = f.readByte() == 0 ? false : true;
e.speed = f.readUnsignedShortLittleEndian();
f.readByte(); // unused
e.movecode = f.readByte();
e.wx1 = f.readUnsignedShortLittleEndian();
e.wy1 = f.readUnsignedShortLittleEndian();
e.wx2 = f.readUnsignedShortLittleEndian();
e.wy2 = f.readUnsignedShortLittleEndian();
e.wdelay = f.readUnsignedShortLittleEndian();
f.readInt(); // unused
e.movescript = f.readFixedString(256);
switch(e.movecode) {
case 0: e.setMotionless(); break;
case 1: e.setWanderZone(); break;
case 2: e.setWanderBox(e.wx1, e.wy1, e.wx2, e.wy2); break;
case 3: e.setMoveScript(e.movescript); break;
}
e.chrname = f.readFixedString(256);
e.description = f.readFixedString(256);
e.script = f.readFixedString(256); // this is the actual script
this.entities[i] = e;
}
// VC Code
f.close();
} catch (IOException e) {
System.err.println("IOException : " + e);
}
}
/**
* Saves a Map to a specified file path
*
*/
public void save(String strFilePath) {
// create FileOutputStream object
try {
FileOutputStream fos = new FileOutputStream(strFilePath);
int vcoffset = this.save(this, fos);
RandomAccessFile raf = new RandomAccessFile(strFilePath, "rw");
raf.seek(10);
raf.writeInt(Integer.reverseBytes(vcoffset));
raf.close();
}
catch(FileNotFoundException fnfe) {
System.err.println("Map::FileNotFoundException : " + strFilePath);
fnfe.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Saves a Map to a specified output stream
*
* @param Map m
* @param OutputStream
*/
public int save(MapVerge m, OutputStream os) {
ExtendedDataOutputStream f = null;
try {
f = new ExtendedDataOutputStream(os);
// Begin to write
f.writeString(MapVerge.MAP_SIGNATURE);
f.writeSignedIntegerLittleEndian(MapVerge.MAP_VERSION);
// Write a dummy offset for now, but this needs to be backpatched,
// once the real map is completed.
int vc = f.size();
f.writeSignedIntegerLittleEndian(0);
f.writeFixedString(m.mapname, 256);
f.writeFixedString(m.vspname, 256);
f.writeFixedString(m.musicname, 256);
f.writeFixedString(m.renderstring, 256);
f.writeFixedString(m.startupscript, 256);
f.writeUnsignedShortLittleEndian(m.startX);
f.writeUnsignedShortLittleEndian(m.startY);
f.writeSignedIntegerLittleEndian(m.layers.length);
for (Layer l : m.layers) {
f.writeFixedString(l.name, 256);
f.writeDoubleLittleEndian(l.parallax_x);
f.writeDoubleLittleEndian(l.parallax_y);
f.writeUnsignedShortLittleEndian(l.width);
f.writeUnsignedShortLittleEndian(l.height);
f.writeUnsignedByte((int) (l.lucent * 100.0)); // Was 100 - (int) (l.lucent * 100.0 + 0.5));
//l.tiledata[0] = 1;
//l.tiledata[1] = 15;
//l.tiledata[2] = 800;
//l.tiledata[3] = 14000;
f.writeCompressedUnsignedShorts(l.tiledata);
}
f.writeCompressedBytes(m.obsLayer);
f.writeCompressedUnsignedShorts(m.zoneLayer);
f.writeSignedIntegerLittleEndian(m.zones.length);
for (Zone z : m.zones) {
f.writeFixedString(z.name, 256);
f.writeFixedString(z.script, 256);
f.writeUnsignedByte(z.percent);
f.writeUnsignedByte(z.delay);
f.writeUnsignedByte(z.method);
}
f.writeSignedIntegerLittleEndian(m.entities.length);
for (Entity e : m.entities) {
f.writeUnsignedShortLittleEndian(e.getx()/16);
f.writeUnsignedShortLittleEndian(e.gety()/16);
f.writeByte(e.face); // 0 or 1
f.writeByte(e.obstructable == false ? 0 : 1);
f.writeByte(e.obstruction == false ? 0 : 1);
f.writeByte(e.autoface == false ? 0 : 1);
f.writeUnsignedShortLittleEndian(e.speed);
f.writeByte(0);
f.writeByte(e.movecode);
f.writeUnsignedShortLittleEndian(e.wx1);
f.writeUnsignedShortLittleEndian(e.wy1);
f.writeUnsignedShortLittleEndian(e.wx2);
f.writeUnsignedShortLittleEndian(e.wy2);
f.writeUnsignedShortLittleEndian(e.wdelay);
f.writeSignedIntegerLittleEndian(0);
f.writeFixedString(e.movescript, 256);
f.writeFixedString(e.chrname, 256);
f.writeFixedString(e.description, 256);
f.writeFixedString(e.script, 256);
}
// Write the vc offset. (Don't need, but see RandomAccessFile)
int end = f.size();
// f.seek(vc);
f.writeSignedIntegerLittleEndian(0);
System.err.println("[Rafael, the Esper]SAVE: " + f.size());
f.close();
return end;
} catch (IOException e) {
System.err.println("IOException : " + e);
}
return 0;
}
// Rafael: Code disassociated with map loading
private void startMap() {
if(!musicname.trim().isEmpty())
playmusic(Script.load(musicname));
current_map = this;
//se.LoadMapScript(f, mapfname);
for(int i=0; i<current_map.getEntities().length; i++) {
Entity e = current_map.getEntities()[i];
e.chr = new CHR(e.chrname); //RequestCHR(e.chrname);
e.index = Script.numentities++;
entity.add(e);
}
//TODO Check if this is needed
//if(this.tileset.numobs == 0)
//this.tileset.numobs = 1;
if(startupscript != null && !startupscript.trim().equals(""))
callfunction(startupscript);
}
// Use
public int getzone(int x, int y) {
if (x < 0 || y < 0 || x >= getWidth() || y >= getHeight())
return 0;
return zoneLayer[(y * getWidth()) + x];
}
public boolean getobs(int x, int y) {
if (x < 0 || y < 0 || x >= getWidth() || y >= getHeight())
return true;
if (obsLayer[(y * getWidth()) + x] == 0)
return false;
return true;
}
public boolean getobspixel(int x, int y) { // modified by [Rafael, the Esper]
if (!horizontalWrapable && (x < 0 || (x >> 4) >= getWidth()))
return true;
if (!verticalWrapable && (y < 0 || (y >> 4) >= getHeight()))
return true;
if(horizontalWrapable && x < 0)
x+= (getWidth() *16);
if(horizontalWrapable && (x >> 4) >= getWidth())
x-= (getWidth() *16);
if(verticalWrapable && y < 0)
y+= (getHeight() *16);
if(verticalWrapable && (y >> 4) >= getHeight())
y-= (getHeight() *16);
int t = obsLayer[((y >> 4) * getWidth()) + (x >> 4)];
return tileset.GetObs(t, x&15, y&15);
}
public int gettile(int x, int y, int i) {
if(i>=this.layers.length)
return 0;
return this.layers[i].getTile(x,y);
}
public void setzone(int x, int y, int z) {
if (x < 0 || y < 0 || x >= getWidth() || y >= getHeight())
return;
if (z >= zones.length)
return;
zoneLayer[(y * getWidth()) + x] = z;
}
public void setobs(int x, int y, int t) {
if (x < 0 || y < 0 || x >= getWidth() || y >= getHeight())
return;
if (t >= tileset.numobs && t!=0)
return;
obsLayer[(y * getWidth()) + x] = (byte) t;
}
public void settile(int x, int y, int layer, int index) {
if(layer>=this.layers.length) {
return;
}
else {
this.layers[layer].setTile(x,y,index);
}
resetCacheArray();
}
public int getWidth() {
if (layers != null && layers[0] != null) {
return layers[0].width;
}
return 0;
}
public int getHeight() {
if (layers != null && layers[0] != null) {
return layers[0].height;
}
return 0;
}
public String getFilename() {
return this.filename;
}
public String getMapname() {
return this.mapname;
}
public Zone[] getZones() {
return this.zones;
}
public Entity[] getEntities() {
return this.entities;
}
public void setRenderstring(String string) {
this.renderstring = string;
}
public String getRenderstring() {
return this.renderstring;
}
public String getScriptZone(int zone) {
if(zones!=null)
return zones[zone].script;
return null;
}
public int getPercentZone(int zone) {
if(zones!=null)
return zones[zone].percent;
return 0;
}
public int getMethodZone(int zone) {
if(zones!=null)
return zones[zone].method;
return 0;
}
public int getNumLayers() {
return this.layers.length;
}
public int getLayerLucent(int layer) {
return layers[layer].lucent;
}
/*
*
*/
static class Layer {
public static final int DEFAULT_X = 30;
public static final int DEFAULT_Y = 20;
private String name = "";
private double parallax_x = 1.0, parallax_y = 1.0;
int width = DEFAULT_X; // Unsigned short
int height = DEFAULT_Y;
private int lucent = 0; // Unsigned Byte
private int x_offset, y_offset; // used to account for changing parallax
int[] tiledata = new int[DEFAULT_X*DEFAULT_Y]; // width * height Unsigned shorts!
public int getTile(int x, int y) {
if (x<0 || y<0 || x>=width || y>=height) return 0;
return tiledata[(y*width)+x];
}
public void setTile(int x, int y, int t) {
if (x<0 || y<0 || x>=width || y>=height) return;
tiledata[(y*width)+x] = t;
}
void setParallaxX(double p, int xwin) { // [Rafael, the Esper]: changed to receive xwin
// increase the x_offset to the current layer pos given the current parallax
x_offset += (int) ((float) xwin * parallax_x);
// then reduce it by what the parallax will be
x_offset -= (int) ((float) xwin * p);
// then we can set the parallax
parallax_x = p;
}
void setParallaxY(double p, int ywin) { // [Rafael, the Esper]: changed to receive ywin
// increase the x_offset to the current layer pos given the current parallax
y_offset += (int) ((float) ywin * parallax_y);
// then reduce it by what the parallax will be
y_offset -= (int) ((float) ywin * p);
// then we can set the parallax
parallax_y = p;
}
public String toString() {
return "Layer " + name + ": (" + parallax_x + ", " + parallax_y + ") (" + width + ", " + height + ") " + lucent + " Data: " + tiledata;
}
}
class Zone {
private String name = "";
private String script = "";
private int percent=255, delay, method; // Unsigned byte
public String toString() {
return "Zone " + name + " Act:" + script + " Chance:" + percent + " Delay:" + delay + " Method:" + method;
}
}
}