diff --git a/.gitignore b/.gitignore
index a1c2a23..5c0636e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,6 +10,11 @@
# Mobile Tools for Java (J2ME)
.mtj.tmp/
+# Custom
+out/
+profiles/
+unused/
+
# Package Files #
*.jar
*.war
@@ -21,3 +26,59 @@
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
+
+.metadata
+bin/
+tmp/
+*.tmp
+*.bak
+*.swp
+*~.nib
+local.properties
+.settings/
+.loadpath
+.recommenders
+
+# External tool builders
+.externalToolBuilders/
+
+# Locally stored "Eclipse launch configurations"
+#*.launch
+
+# PyDev specific (Python IDE for Eclipse)
+*.pydevproject
+
+# CDT-specific (C/C++ Development Tooling)
+.cproject
+
+# CDT- autotools
+.autotools
+
+# Java annotation processor (APT)
+.factorypath
+
+# PDT-specific (PHP Development Tools)
+.buildpath
+
+# sbteclipse plugin
+.target
+
+# Tern plugin
+.tern-project
+
+# TeXlipse plugin
+.texlipse
+
+# STS (Spring Tool Suite)
+.springBeans
+
+# Code Recommenders
+.recommenders/
+
+# Annotation Processing
+.apt_generated/
+
+# Scala IDE specific (Scala & Java development for Eclipse)
+.cache-main
+.scala_dependencies
+.worksheet
diff --git a/MetroidMapGuardian/.classpath b/MetroidMapGuardian/.classpath
new file mode 100644
index 0000000..b5455e0
--- /dev/null
+++ b/MetroidMapGuardian/.classpath
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/MetroidMapGuardian/.project b/MetroidMapGuardian/.project
new file mode 100644
index 0000000..f69c995
--- /dev/null
+++ b/MetroidMapGuardian/.project
@@ -0,0 +1,47 @@
+
+
+ MetroidMapGuardian
+ A map viewer and powerup collector for the Metroid Prime Trilogy.
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.ui.externaltools.ExternalToolBuilder
+ full,incremental,
+
+
+ LaunchConfigHandle
+ <project>/builder.launch
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
+
+ 1558289867571
+
+ 10
+
+ org.eclipse.ui.ide.multiFilter
+ 1.0-name-matches-false-false-bin
+
+
+
+ 1558289867580
+
+ 10
+
+ org.eclipse.ui.ide.multiFilter
+ 1.0-name-matches-false-false-profiles
+
+
+
+
diff --git a/MetroidMapGuardian/build.xml b/MetroidMapGuardian/build.xml
new file mode 100644
index 0000000..c891593
--- /dev/null
+++ b/MetroidMapGuardian/build.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MetroidMapGuardian/builder.launch b/MetroidMapGuardian/builder.launch
new file mode 100644
index 0000000..e74bc0c
--- /dev/null
+++ b/MetroidMapGuardian/builder.launch
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MetroidMapGuardian/src/entity/Entity.java b/MetroidMapGuardian/src/entity/Entity.java
new file mode 100644
index 0000000..54d68fc
--- /dev/null
+++ b/MetroidMapGuardian/src/entity/Entity.java
@@ -0,0 +1,208 @@
+package entity;
+
+import java.awt.Graphics2D;
+
+import nbt.NBTTagCompound;
+
+import room.Room;
+import game.GameInstance;
+import game.Trilogy;
+import geometry.Rectangle;
+import geometry.Vector;
+
+/**
+ * A base class for all objects that are contained in, and interact with the map.
+ *
+ * @author Robert Jordan
+ *
+ * @see
+ * {@linkplain Map},
+ * {@linkplain GameInstance}
+ */
+public abstract class Entity {
+
+ // =================== Private Members ====================
+
+ /**
+ * The last known direction of the entity. This is used when
+ * the entities velocity is 0.
+ */
+ private double lastDirection;
+
+ // ==================== Public Members ====================
+
+ /** The game this entity is linked to. */
+ public GameInstance instance;
+ public Trilogy trilogy;
+ /** The room that contains this entity. */
+ public Room room;
+ /**
+ * A string that represents a way to access the entity without receiving
+ * information about it in advance.
+ */
+ public String id;
+ /**
+ * The draw depth of the entity, entities with higher depths will draw
+ * before entities with lower depths.
+ */
+ public int depth;
+ /** The position on the map of the entity. */
+ public Vector position;
+ /** The speed of the entity in units per update. */
+ public Vector velocity;
+
+ public Rectangle bounds;
+ /** True if the entity has been destroyed. */
+ public boolean destroyed;
+
+ // ===================== Constructors =====================
+
+ /**
+ * The default constructor, constructs an entity at (0, 0).
+ *
+ * @return Returns the default entity.
+ */
+ protected Entity() {
+ this.instance = null;
+ this.trilogy = null;
+ this.room = null;
+
+ this.id = "";
+ this.depth = 0;
+
+ this.position = new Vector();
+ this.velocity = new Vector();
+ this.lastDirection = 0.0;
+
+ }
+ /**
+ * Constructs an entity with the specified details.
+ *
+ * @param id - The key identifier of the entity.
+ * @param depth - The depth of the entity.
+ * @param position - The position of the entity.
+ * @param velocity - The velocity of the entity.
+ * @return Returns an entity with the specified details.
+ */
+ protected Entity(String id, int depth, Vector position, Vector velocity) {
+ this.instance = null;
+ this.trilogy = null;
+ this.room = null;
+
+ this.id = id;
+ this.depth = depth;
+
+ this.position = new Vector(position);
+ this.velocity = new Vector(velocity);
+ this.lastDirection = 0.0;
+
+ }
+ /**
+ * Constructs the entity from an NBT compound of values. This is mainly used
+ * To load entire maps from file in NBT format.
+ *
+ * @param nbt - The compound containing the tags related to the entity.
+ * @return Returns the entity constructed from tag data.
+ *
+ * @see
+ * {@linkplain NBTElement},
+ * {@linkplain NBTTagCompound}
+ */
+ protected Entity(NBTTagCompound nbt) {
+ instance = null;
+ trilogy = null;
+ room = null;
+
+ id = nbt.getString("id", "");
+ depth = nbt.getInteger("depth");
+
+ if (nbt.hasKey("speed") || nbt.hasKey("direction"))
+ velocity = new Vector(nbt.getDouble("speed"), nbt.getDouble("direction"), true);
+ else
+ velocity = new Vector(nbt.getDouble("hspeed"), nbt.getDouble("vspeed"));
+ position = new Vector(nbt.getDouble("x"), nbt.getDouble("y"));
+ lastDirection = nbt.getDouble("direction");
+
+ }
+ /**
+ * Initializes the entity by setting the game instance it is linked to.
+ *
+ * @param room - The room that contains the entity.
+ * @param instance - The game instance that contains the room.
+ */
+ public void initialize(Room room, GameInstance instance, Trilogy trilogy) {
+ this.room = room;
+ this.trilogy = trilogy;
+ this.instance = instance;
+ }
+
+ // ===================== NBT File IO ======================
+
+ /**
+ * Saves tag information about the entity to the NBT compound.
+ *
+ * @param nbt - The NBT compound to save tag information to.
+ *
+ * @see
+ * {@linkplain NBTTagCompound}
+ */
+ public void saveEntity(NBTTagCompound nbt) {
+ nbt.setString( "id", id);
+ nbt.setInteger( "depth", depth);
+ nbt.setDouble( "x", position.x);
+ nbt.setDouble( "y", position.y);
+ nbt.setDouble( "hspeed", velocity.x);
+ nbt.setDouble( "vspeed", velocity.y);
+ nbt.setDouble( "lastDirection", lastDirection);
+ }
+ /**
+ * Saves the entity to an NBT compound tag.
+ *
+ * @return Returns the NBT compound containing the values on the entity.
+ *
+ * @see
+ * {@linkplain NBTTagCompound}
+ */
+ public abstract NBTTagCompound saveEntity();
+ /**
+ * Creates an entity based on the information given from an NBT compound. The
+ * entity must first be defined in EntityLoader in order to be loaded from a
+ * map file.
+ *
+ * @param nbt - The NBT compound containing tag information on the entity.
+ * @return Returns an entity constructed from the specified tag information.
+ *
+ * @see
+ * {@linkplain NBTTagCompound},
+ * {@linkplain EntityLoader}
+ */
+ public abstract Entity loadEntity(NBTTagCompound nbt);
+
+ // ======================== Updating ========================
+
+ /**
+ * Called every step for the entity to perform actions and update.
+ */
+ public void update() {
+
+ // Update position
+ position.add(velocity);
+
+ }
+ /**
+ * Called every step for the entity to draw to the screen.
+ *
+ * @param g - The graphics object to draw to.
+ */
+ public void draw(Graphics2D g) {
+
+ }
+ /**
+ * Destroys the entity and marks it for removal.
+ */
+ public void destroy() {
+ destroyed = true;
+ }
+
+}
+
diff --git a/MetroidMapGuardian/src/entity/EntityLoader.java b/MetroidMapGuardian/src/entity/EntityLoader.java
new file mode 100644
index 0000000..b71d427
--- /dev/null
+++ b/MetroidMapGuardian/src/entity/EntityLoader.java
@@ -0,0 +1,51 @@
+package entity;
+
+import java.util.HashMap;
+
+import nbt.NBTTagCompound;
+
+public class EntityLoader {
+
+ // ==================== Static Members ====================
+
+ /** The map that contains entities linked to class names. */
+ private static HashMap entityMap = new HashMap();
+
+ // ==================== Static Methods ====================
+
+ /**
+ * Registers a class name with the specified entity so it can be linked
+ * during map construction.
+ *
+ * @param className - The class name for the entity.
+ * @param entity - The entity class to register.
+ */
+ private static void register(String className, Entity entity) {
+ entityMap.put(className, entity);
+ }
+ /**
+ * Called at the beginning of the program to register and link all class
+ * names to entities.
+ */
+ public static void registerEntities() {
+
+ // Living
+ register("Marker", new Marker());
+ }
+ /**
+ * Creates an entity based on the information given from an NBT compound.
+ *
+ * @param nbt - The NBT compound containing tag information on the entity.
+ * @return Returns the loaded entity.
+ */
+ public static Entity loadEntity(NBTTagCompound nbt) {
+
+ String className = nbt.getString("class", "");
+
+ if (entityMap.containsKey(className))
+ return entityMap.get(className).loadEntity(nbt);
+
+ return null;
+ }
+
+}
diff --git a/MetroidMapGuardian/src/entity/Marker.java b/MetroidMapGuardian/src/entity/Marker.java
new file mode 100644
index 0000000..2f18b4d
--- /dev/null
+++ b/MetroidMapGuardian/src/entity/Marker.java
@@ -0,0 +1,311 @@
+package entity;
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.RadialGradientPaint;
+import java.awt.RenderingHints;
+import java.awt.image.BufferedImage;
+
+import javax.swing.JOptionPane;
+
+import room.Room;
+import game.GameInstance;
+import game.PowerUp;
+import game.Profile;
+import game.Trilogy;
+import geometry.Rectangle;
+import geometry.Vector;
+import graphics.Draw;
+import graphics.MarkerDetails;
+import graphics.PopupMarkerDetails;
+import graphics.ScalableImage;
+import main.Keyboard;
+import main.Mouse;
+import nbt.NBTTagCompound;
+
+/**
+ * The marker used for checking off items completed on the map. Each marker
+ * stores and index and type of the power up, the power up information is
+ * then looked up based on that information.
+ *
+ * @author Robert Jordan
+ * @see
+ * {@linkplain PowerUp}
+ */
+public class Marker extends Entity {
+
+ // ==================== Static Members ====================
+
+ /** The image to display when the marker has been checked off. */
+ public static ScalableImage imageChecked = new ScalableImage("checked", "",
+ BufferedImage.TYPE_INT_ARGB, RenderingHints.VALUE_INTERPOLATION_BICUBIC, 1.0);
+ /** The image to display when the marker is unchecked and unchecked markers are visible. */
+ public static ScalableImage imageUnchecked = new ScalableImage("unchecked", "",
+ BufferedImage.TYPE_INT_ARGB, RenderingHints.VALUE_INTERPOLATION_BICUBIC, 1.0);
+
+ // ======================= Members ========================
+
+ /** The name of the marker type. */
+ public int type;
+ /** The index of the marker. */
+ public int index;
+ /** The secondary type of the marker. */
+ public int linkedType;
+ /** The secondary index of the marker. */
+ public int linkedIndex;
+
+ /** True if the mouse is hovering over the marker. */
+ public boolean hovering;
+ /** A debug feature used in the editor. */
+ public boolean placing;
+
+ // ===================== Constructors =====================
+
+ /**
+ * The default constructor, constructs a marker.
+ *
+ * @return Returns the default marker.
+ */
+ public Marker() {
+ super();
+ this.type = 0;
+ this.index = 0;
+ this.linkedType = -1;
+ this.linkedIndex = 0;
+
+ this.hovering = false;
+ this.placing = false;
+ }
+ /**
+ * Constructs a marker at the given coordinates.
+ *
+ * @param type - The name of the marker type.
+ * @param index - The index of the marker.
+ * @return Returns a marker at the given coordinates.
+ */
+ public Marker(int type, int index) {
+ super();
+ this.type = type;
+ this.index = index;
+ this.linkedType = -1;
+ this.linkedIndex = 0;
+
+ this.hovering = false;
+ this.placing = false;
+ }
+ /**
+ * Constructs the entity from an NBT compound of values. This is mainly used
+ * To load entire maps from file in NBT format.
+ *
+ * @param nbt - The compound containing the tags related to the entity.
+ * @return Returns the entity constructed from tag data.
+ *
+ * @see
+ * {@linkplain NBTElement},
+ * {@linkplain NBTTagCompound}
+ */
+ public Marker(NBTTagCompound nbt) {
+ super(nbt);
+ this.type = nbt.getInteger("type", 0);
+ this.index = nbt.getInteger("index", 0);
+ this.linkedType = nbt.getInteger("linkedType", -1);
+ this.linkedIndex = nbt.getInteger("linkedIndex", 0);
+
+ this.hovering = false;
+ this.placing = false;
+
+ if (linkedType == type) {
+ linkedType = -1;
+ linkedIndex = 0;
+ }
+ }
+ /**
+ * Initializes the entity by setting the game instance it is linked to.
+ *
+ * @param room - The room that contains the entity.
+ * @param instance - The game instance that contains the room.
+ */
+ public void initialize(Room room, GameInstance instance, Trilogy trilogy) {
+ super.initialize(room, instance, trilogy);
+ }
+
+ // ===================== NBT File IO ======================
+
+ /**
+ * Saves tag information about the entity to the NBT compound.
+ *
+ * @param nbt - The NBT compound to save tag information to.
+ *
+ * @see
+ * {@linkplain NBTTagCompound}
+ */
+ public void saveEntity(NBTTagCompound nbt) {
+ super.saveEntity(nbt);
+
+ nbt.setInteger( "type", type);
+ nbt.setInteger( "index", index);
+ nbt.setInteger( "linkedType", linkedType);
+ nbt.setInteger( "linkedIndex", linkedIndex);
+ }
+ /**
+ * Saves the entity to an NBT compound tag.
+ *
+ * @return Returns the NBT compound containing the values on the entity.
+ *
+ * @see
+ * {@linkplain NBTTagCompound}
+ */
+ public NBTTagCompound saveEntity() {
+ NBTTagCompound nbt = new NBTTagCompound();
+ nbt.setString("class", "Marker");
+ saveEntity(nbt);
+ return nbt;
+ }
+ /**
+ * Creates an entity based on the information given from an NBT compound. The
+ * entity must first be defined in EntityLoader in order to be loaded from a
+ * map file.
+ *
+ * @param nbt - The NBT compound containing tag information on the entity.
+ * @return Returns an entity constructed from the specified tag information.
+ *
+ * @see
+ * {@linkplain NBTTagCompound},
+ * {@linkplain EntityLoader}
+ */
+ public Marker loadEntity(NBTTagCompound nbt) {
+ return new Marker(nbt);
+ }
+
+ // ======================== Updating ========================
+
+ /**
+ * Called every step for the entity to perform actions and update.
+ */
+ public void update() {
+
+ double radius = (double)imageChecked.getWidth() / 2.0;
+ Vector radiusVec = new Vector(radius, radius);
+ Rectangle rect = new Rectangle(position.minus(radiusVec), radiusVec.scaledBy(2.0));
+
+ if (rect.contains(room.view.getMousePoint()) && !room.isMouseOverGUI) {
+ // Create the marker display
+ if (!hovering) {
+ room.addGui(new MarkerDetails(this));
+ }
+ hovering = true;
+
+ if (Mouse.left.pressed() && !instance.editorMode) {
+ trilogy.checkPowerUp(type, index);
+ if (linkedType != -1)
+ trilogy.checkPowerUp(linkedType, linkedIndex);
+ new Profile(instance).saveProfile();
+ }
+ else if (Mouse.right.pressed() && !instance.editorMode) {
+ room.addGui(new PopupMarkerDetails(this));
+ }
+ }
+ else {
+ hovering = false;
+ }
+
+ if (instance.editorMode) {
+ try {
+ if (placing) {
+ position = room.view.getMousePoint();
+ if (Mouse.middle.released())
+ placing = false;
+ }
+ else if (hovering) {
+ if (Mouse.left.pressed()) {
+ if (Keyboard.control.down() && !Keyboard.shift.down()) {
+ String num = JOptionPane.showInputDialog(null, "New Marker Index", Integer.toString(index + 1), JOptionPane.OK_CANCEL_OPTION);
+ index = Integer.parseInt(num) - 1;
+ Keyboard.reset();
+ Mouse.reset();
+ }
+ else if (Keyboard.control.down() && Keyboard.shift.down()) {
+ String num = JOptionPane.showInputDialog(null, "New Marker Linked Index", Integer.toString(linkedIndex + 1), JOptionPane.OK_CANCEL_OPTION);
+ linkedIndex = Integer.parseInt(num) - 1;
+ Keyboard.reset();
+ Mouse.reset();
+ }
+ else if (!Keyboard.control.down() && Keyboard.shift.down()) {
+ String num = JOptionPane.showInputDialog(null, "New Marker Linked Type", Integer.toString(linkedType), JOptionPane.OK_CANCEL_OPTION);
+ linkedType = Integer.parseInt(num);
+ Keyboard.reset();
+ Mouse.reset();
+ }
+ else {
+ trilogy.checkPowerUp(type, index);
+ if (linkedType != -1)
+ trilogy.checkPowerUp(linkedType, linkedIndex);
+ }
+ }
+ else if (Mouse.right.pressed()) {
+ destroy();
+ }
+ }
+ }
+ catch (NumberFormatException e) {
+
+ }
+ }
+
+ super.update();
+ }
+ /**
+ * Called every step for the entity to draw to the screen.
+ *
+ * @param g - The graphics object to draw to.
+ */
+ public void draw(Graphics2D g) {
+
+ double radius = (double)imageChecked.getWidth() / 2.0 * imageChecked.getScale();
+ Vector point = room.view.getViewPoint(position);
+
+ Vector radiusVec = new Vector(radius, radius);
+
+ // Draw check image
+ if (getPowerUp().collected)
+ Draw.drawImage(g, imageChecked.getScaledImage(), point.minus(radiusVec));
+ else if(instance.showUncheckedMarkers)
+ Draw.drawImage(g, imageUnchecked.getScaledImage(), point.minus(radiusVec));
+
+ // Draw the bright circle to emphasize highlighting
+ if (hovering) {
+ g.setPaint(new RadialGradientPaint((float)point.x, (float)point.y, (float)radius, new float[]{0.0f, 1.0f},
+ new Color[]{new Color(255, 255, 255, 200), new Color(255, 255, 255, 20)}));
+
+ Draw.fillEllipse(g, point, radiusVec, true);
+ }
+
+ // Draw a red circle to aid in placing
+ if (placing) {
+ g.setColor(new Color(255, 0, 0));
+ Draw.drawEllipse(g, point, radiusVec, true);
+ }
+
+ }
+
+ // ==================== Marker Methods ====================
+
+ /**
+ * Called when the mouse is hovering over the marker.
+ */
+ public PowerUp getPowerUp() {
+ return trilogy.getPowerUp(type, index);
+ }
+ /**
+ * Called when the mouse is hovering over the marker.
+ */
+ public PowerUp getLinkedPowerUp() {
+ return trilogy.getPowerUp(linkedType, linkedIndex);
+ }
+ public boolean hasLinkedPowerUp() {
+ return linkedType != -1;
+ }
+
+}
+
+
diff --git a/MetroidMapGuardian/src/entity/Surge.java b/MetroidMapGuardian/src/entity/Surge.java
new file mode 100644
index 0000000..d64f4ea
--- /dev/null
+++ b/MetroidMapGuardian/src/entity/Surge.java
@@ -0,0 +1,148 @@
+package entity;
+
+import game.GameInstance;
+import game.Trilogy;
+import geometry.Vector;
+import graphics.Draw;
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+
+import room.Room;
+import main.Main;
+import nbt.NBTTagCompound;
+
+/**
+ *
+ * @author Robert Jordan
+ *
+ */
+public class Surge extends Entity {
+
+ // ======================= Members ========================
+
+ /** The length of the surge. */
+ public int length;
+
+ // ===================== Constructors =====================
+
+ /**
+ * The default constructor, constructs a marker.
+ *
+ * @return Returns the default marker.
+ */
+ public Surge() {
+ super();
+ this.length = 80;
+ this.velocity.y = 2;
+ }
+ /**
+ * Constructs a marker at the given coordinates.
+ *
+ * @param type - The name of the marker type.
+ * @param index - The index of the marker.
+ * @return Returns a marker at the given coordinates.
+ */
+ public Surge(double x, double vspeed, int length) {
+ super();
+ this.length = length;
+ this.velocity.y = vspeed;
+ if (vspeed < 0.0)
+ this.position = new Vector(x, Main.frame.getHeight());
+ else
+ this.position = new Vector(x, -length);
+ }
+ /**
+ * Constructs the entity from an NBT compound of values. This is mainly used
+ * To load entire maps from file in NBT format.
+ *
+ * @param nbt - The compound containing the tags related to the entity.
+ * @return Returns the entity constructed from tag data.
+ *
+ * @see
+ * {@linkplain NBTElement},
+ * {@linkplain NBTTagCompound}
+ */
+ public Surge(NBTTagCompound nbt) {
+ super(nbt);
+ this.length = nbt.getInteger("length");
+ }
+ /**
+ * Initializes the entity by setting the game instance it is linked to.
+ *
+ * @param room - The room that contains the entity.
+ * @param instance - The game instance that contains the room.
+ */
+ public void initialize(Room room, GameInstance instance, Trilogy trilogy) {
+ super.initialize(room, instance, trilogy);
+ }
+
+ // ===================== NBT File IO ======================
+
+ /**
+ * Saves tag information about the entity to the NBT compound.
+ *
+ * @param nbt - The NBT compound to save tag information to.
+ *
+ * @see
+ * {@linkplain NBTTagCompound}
+ */
+ public void saveEntity(NBTTagCompound nbt) {
+ super.saveEntity(nbt);
+
+ nbt.setInteger( "length", length);
+ }
+ /**
+ * Saves the entity to an NBT compound tag.
+ *
+ * @return Returns the NBT compound containing the values on the entity.
+ *
+ * @see
+ * {@linkplain NBTTagCompound}
+ */
+ public NBTTagCompound saveEntity() {
+ NBTTagCompound nbt = new NBTTagCompound();
+ nbt.setString("class", "Surge");
+ saveEntity(nbt);
+ return nbt;
+ }
+ /**
+ * Creates an entity based on the information given from an NBT compound. The
+ * entity must first be defined in EntityLoader in order to be loaded from a
+ * map file.
+ *
+ * @param nbt - The NBT compound containing tag information on the entity.
+ * @return Returns an entity constructed from the specified tag information.
+ *
+ * @see
+ * {@linkplain NBTTagCompound},
+ * {@linkplain EntityLoader}
+ */
+ public Surge loadEntity(NBTTagCompound nbt) {
+ return new Surge(nbt);
+ }
+
+ // ======================== Updating ========================
+
+ /**
+ * Called every step for the entity to perform actions and update.
+ */
+ public void update() {
+ super.update();
+
+ if ((velocity.y < 0.0 && position.y < -length) ||
+ (velocity.y > 0.0 && position.y > Main.frame.getContentPane().getHeight())) {
+ destroy();
+ }
+ }
+ /**
+ * Called every step for the entity to draw to the screen.
+ *
+ * @param g - The graphics object to draw to.
+ */
+ public void draw(Graphics2D g) {
+ g.setColor(new Color(50, 70, 100));
+ Draw.drawLine(g, position, position.plus(0, length));
+ }
+
+}
diff --git a/MetroidMapGuardian/src/game/GameInstance.java b/MetroidMapGuardian/src/game/GameInstance.java
new file mode 100644
index 0000000..87e0bd5
--- /dev/null
+++ b/MetroidMapGuardian/src/game/GameInstance.java
@@ -0,0 +1,304 @@
+package game;
+
+import geometry.Vector;
+import graphics.Draw;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.Stroke;
+import java.awt.event.KeyEvent;
+import java.util.ArrayList;
+
+import javax.swing.JOptionPane;
+
+import entity.Marker;
+import main.ImageLoader;
+import main.Keyboard;
+import main.Mouse;
+import nbt.NBTElement;
+import nbt.NBTTagCompound;
+import nbt.NBTTagList;
+
+import room.Map;
+import room.Menu;
+import room.Room;
+
+/**
+ * The instance that stores all game information.
+ *
+ * @author Robert Jordan
+ * @see
+ * {@linkplain Profile},
+ * {@linkplain Trilogy},
+ * {@linkplain Map}
+ */
+public class GameInstance {
+
+ // ======================= Members ========================
+
+ public static boolean PROGRAMMER_MODE = false;
+
+ /** The list of trilogies. */
+ public ArrayList trilogies;
+ /** The index of the current trilogy. */
+ public int currentTrilogy;
+ /** The current trilogy. */
+ public Trilogy trilogy;
+ /** The name of the current profile to save to. */
+ public String profileName;
+ /** The current room that is running. */
+ public Room room;
+ public Menu menu;
+ public boolean inMenu;
+
+ /** Setting to show unchecked markers as red chozo symbols. */
+ public boolean showUncheckedMarkers;
+
+ // ===================== Debug Mode =======================
+
+ /** True if editor mode is enabled to place power ups. */
+ public boolean editorMode;
+ /** The current power up to place in editor mode. */
+ public int currentPowerUp;
+
+ // ===================== Constructors =====================
+
+ /**
+ * The default constructor, constructs an entity at (0, 0).
+ *
+ * @return Returns the default entity.
+ */
+ public GameInstance() {
+
+ editorMode = false;
+ currentPowerUp = PowerUp.MISSILE_EXPANSION;
+ showUncheckedMarkers = false;
+ profileName = "";
+ trilogies = new ArrayList();
+ inMenu = true;
+ menu = new Menu();
+
+ NBTTagCompound nbt = NBTElement.loadNBTCompound("/resources/data/map.dat", true).getCompound("MetroidMapData");
+ NBTTagList trilogyList = nbt.getList("trilogies");
+
+ for (NBTElement tag : trilogyList.getTags()) {
+ Trilogy t = new Trilogy((NBTTagCompound)tag);
+ trilogies.add(t);
+ }
+
+ trilogy = trilogies.get(0);
+ }
+ /**
+ * Initializes game instance.
+ */
+ public void initialize() {
+
+ for (Trilogy t : trilogies) {
+ t.initialize(this);
+ }
+ changeTrilogy(1);
+ menu.initialize(this, null);
+ }
+
+ // ======================== Updating ========================
+
+ /**
+ * Called every step for the game to perform actions and update.
+ */
+ public void update() {
+
+ if (Keyboard.getKey(KeyEvent.VK_S).pressed() && editorMode) {
+ NBTTagCompound root = new NBTTagCompound("root");
+ NBTTagCompound nbt = new NBTTagCompound("MetroidMapData");
+ NBTTagList trilogyList = new NBTTagList("trilogies", NBTElement.TAG_COMPOUND);
+
+ for (Trilogy t : trilogies) {
+ NBTTagCompound trilogyTag = new NBTTagCompound();
+ trilogyTag.setString("name", t.name);
+ trilogyTag.setString("rawName", t.rawName);
+ trilogyTag.setByte("game", (byte)t.game);
+ NBTTagList mapList = new NBTTagList("maps", NBTElement.TAG_COMPOUND);
+
+ for (Map m : t.maps) {
+ NBTTagCompound mapTag = m.saveRoom();
+ mapList.addCompound(mapTag);
+ }
+
+ trilogyTag.setList("maps", mapList);
+ trilogyList.addCompound(trilogyTag);
+ }
+ nbt.setList("trilogies", trilogyList);
+ root.setCompound("MetroidMapData", nbt);
+ NBTElement.saveNBTCompound("map.dat", root);
+ System.out.println("Levels Saved in New Format.");
+ }
+ else if (Keyboard.getKey(KeyEvent.VK_L).pressed() && editorMode) {
+ NBTTagCompound nbt = NBTElement.loadNBTCompound("map.dat", false);
+ nbt = nbt.getCompound("MetroidMaps", null);
+ for (Trilogy t : trilogies) {
+ NBTTagCompound game = nbt.getCompound(t.rawName, null);
+ for (int i = 0; i < t.maps.size(); i++) {
+ NBTTagCompound map = game.getCompound(t.maps.get(i).rawName, null);
+ t.maps.set(i, t.maps.get(i).loadRoom(map));
+ t.maps.get(i).initialize(this, t);
+ }
+ t.map = t.maps.get(t.currentMap);
+ }
+ System.out.println("Levels Loaded.");
+ }
+
+ if (Keyboard.getKey(KeyEvent.VK_F4).pressed() && PROGRAMMER_MODE)
+ editorMode = !editorMode;
+
+
+ if (Keyboard.getKey(KeyEvent.VK_1).pressed())
+ currentPowerUp = 0;
+ if (Keyboard.getKey(KeyEvent.VK_2).pressed())
+ currentPowerUp = 1;
+ if (Keyboard.getKey(KeyEvent.VK_3).pressed())
+ currentPowerUp = 2;
+ if (Keyboard.getKey(KeyEvent.VK_4).pressed())
+ currentPowerUp = 3;
+ if (Keyboard.getKey(KeyEvent.VK_5).pressed())
+ currentPowerUp = 4;
+ if (Keyboard.getKey(KeyEvent.VK_6).pressed())
+ currentPowerUp = 5;
+ if (Keyboard.getKey(KeyEvent.VK_7).pressed())
+ currentPowerUp = 6;
+ if (Keyboard.getKey(KeyEvent.VK_8).pressed())
+ currentPowerUp = 7;
+ if (Keyboard.getKey(KeyEvent.VK_9).pressed())
+ currentPowerUp = 8;
+ if (Keyboard.getKey(KeyEvent.VK_0).pressed())
+ currentPowerUp = 9;
+ if (Keyboard.getKey(KeyEvent.VK_MINUS).pressed())
+ currentPowerUp = 10;
+
+ if (Keyboard.insert.pressed()) {
+ showUncheckedMarkers = !showUncheckedMarkers;
+ }
+ if (Keyboard.enter.pressed() && editorMode) {
+ ArrayList> collection = new ArrayList>();
+ for(int i = 0; i < trilogy.powerUps.size(); i++) {
+ collection.add(new ArrayList());
+ for (int j = 0; j < trilogy.powerUps.get(i).size(); j++) {
+ collection.get(i).add(0);
+ }
+ }
+ for (int i = 0; i < trilogy.maps.size(); i++) {
+ for (int j = 0; j < trilogy.maps.get(i).entities.size(); j++) {
+ if (trilogy.maps.get(i).entities.get(j) instanceof Marker) {
+ Marker marker = (Marker)trilogy.maps.get(i).entities.get(j);
+ collection.get(marker.type).set(marker.index, collection.get(marker.type).get(marker.index) + 1);
+ if (marker.hasLinkedPowerUp()) {
+ collection.get(marker.linkedType).set(marker.linkedIndex, collection.get(marker.linkedType).get(marker.linkedIndex) + 1);
+ }
+ }
+ }
+ }
+ int type = -1;
+ int index = 0;
+ for(int i = 0; i < collection.size(); i++) {
+ for (int j = 0; j < collection.get(i).size(); j++) {
+ if (collection.get(i).get(j) != 1) {
+ type = i;
+ index = j;
+ }
+ }
+ }
+ if (type != -1) {
+ boolean zero = (collection.get(type).get(index) == 0);
+ JOptionPane.showMessageDialog(null, "Number of power-ups for " + trilogy.getPowerUp(type, index).getTypeName() +
+ ": " + trilogy.getPowerUp(type, index).name + " is " +
+ (zero ? "less than" : "greater than") + " one.", "Power Up Collection Check", JOptionPane.ERROR_MESSAGE);
+ Keyboard.reset();
+ Mouse.reset();
+
+ }
+ else {
+ JOptionPane.showMessageDialog(null, "All collectables are correct", "Power Up Collection Check", JOptionPane.PLAIN_MESSAGE);
+ Keyboard.reset();
+ Mouse.reset();
+
+ }
+ }
+
+ // Update the map
+ if (inMenu)
+ menu.update();
+ else
+ trilogy.map.update();
+ }
+ /**
+ * Called every step for the game to draw to the screen.
+ *
+ * @param g - The graphics object to draw to.
+ */
+ public void draw(Graphics2D g) {
+
+ g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+ g.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
+ g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
+
+ // Draw the map
+ if (inMenu)
+ menu.draw(g);
+ else
+ trilogy.map.draw(g);
+
+ if (editorMode) {
+ g.setFont(new Font("Eurostar Black", Font.PLAIN, 16));
+ Stroke oldStroke = g.getStroke();
+ g.setStroke(new BasicStroke(2.2f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
+ //g.setColor(Color.WHITE);
+ g.setColor(Color.BLACK);
+ Draw.drawStringOutline(g, PowerUp.getPowerUpName(currentPowerUp), 24, 160, 0);//Draw.ALIGN_TOP);
+ g.setStroke(oldStroke);
+
+ //g.setColor(new Color(33, 189, 222));
+ g.setColor(Color.WHITE);
+ Draw.drawString(g, PowerUp.getPowerUpName(currentPowerUp), 24, 160, 0);//Draw.ALIGN_TOP);
+ oldStroke = g.getStroke();
+ g.setStroke(new BasicStroke(0.3f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
+ //g.setColor(Color.WHITE);
+ g.setColor(Color.BLACK);
+ //Draw.drawStringOutline(g, PowerUp.getPowerUpName(currentPowerUp), 24, 160, 0);//Draw.ALIGN_TOP);
+ g.setStroke(oldStroke);
+ }
+ }
+
+ public void changeTrilogy(int game) {
+ trilogy.map.image.unloadScaledImage();
+ ImageLoader.unloadImage(trilogy.rawName + "/maps/" + trilogy.map.rawName, trilogy.rawName);
+ currentTrilogy = game - 1;
+ trilogy = trilogies.get(game - 1);
+ ImageLoader.loadImage(trilogy.rawName + "/maps/" + trilogy.map.rawName, trilogy.rawName);
+ }
+
+ public void loadProfile(Profile profile) {
+
+ profileName = profile.profileName;
+ currentTrilogy = profile.currentTrilogy;
+ trilogy = trilogies.get(currentTrilogy);
+
+ for (int i = 0; i < trilogies.size(); i++) {
+ TrilogyInfo t = profile.trilogies.get(i);
+ trilogies.get(i).currentMap = t.currentMap;
+ trilogies.get(i).map = trilogies.get(i).maps.get(t.currentMap);
+ for (int j = 0; j < t.powerUpsCollected.size(); j++) {
+ for (int k = 0; k < t.powerUpsCollected.get(j).size(); k++) {
+ trilogies.get(i).powerUps.get(j).get(k).collected = t.powerUpsCollected.get(j).get(k);
+ }
+ }
+ for (int j = 0; j < t.mapPans.size(); j++) {
+ trilogies.get(i).maps.get(j).view.pan = new Vector(t.mapPans.get(j));
+ trilogies.get(i).maps.get(j).view.zoom = t.mapZooms.get(j);
+ }
+ }
+ trilogy.changeMap(trilogy.currentMap);
+ }
+}
diff --git a/MetroidMapGuardian/src/game/PowerUp.java b/MetroidMapGuardian/src/game/PowerUp.java
new file mode 100644
index 0000000..25baad8
--- /dev/null
+++ b/MetroidMapGuardian/src/game/PowerUp.java
@@ -0,0 +1,237 @@
+package game;
+
+import java.awt.Color;
+import java.awt.Image;
+
+import main.ImageLoader;
+
+/**
+ * The class used to store data about each collectable in each game. PowerUps
+ * are referenced by Marker entities in maps.
+ *
+ * @author Robert Jordan
+ * @see
+ * {@linkplain Marker}
+ */
+public class PowerUp {
+
+ // =================== Static Variables ===================
+
+ /** The number of power up types. */
+ public static final int NUM_TYPES = 11;
+
+ public static final int SUIT_EXPANSION = 0;
+ public static final int MISSILE_EXPANSION = 1;
+ public static final int ENERGY_TANK = 2;
+ public static final int POWER_BOMB = 3;
+
+ public static final int ARTIFACT = 4;
+
+ public static final int BEAM_AMMO_EXPANSION = 5;
+ public static final int TEMPLE_KEY = 6;
+ public static final int SKY_TEMPLE_KEY = 7;
+
+ public static final int SHIP_MISSILE_EXPANSION = 8;
+ public static final int ENERGY_CELL = 9;
+ public static final int RED_PHAZOID = 10;
+
+ // ======================= Members ========================
+
+ /** The type of the power up. */
+ public int type;
+ /** The name of the power up. */
+ public String name;
+ /** The location of the power up. */
+ public String location;
+ /** The description to acquire the power up. */
+ public String description;
+ /** True if the power up has been checked off. */
+ public boolean collected;
+
+ // ===================== Constructors =====================
+
+ /**
+ * The default constructor, constructs a power up as a suit expansion.
+ *
+ * @return Returns the default power up.
+ */
+ public PowerUp() {
+ this.type = 0;
+ this.name = "";
+ this.location = "";
+ this.description = "";
+ this.collected = false;
+ }
+ /**
+ * Constructs a power up of the given type.
+ *
+ * @param type - The type of power up.
+ * @return Returns the power up of the specified type.
+ */
+ public PowerUp(int type) {
+ this.type = type;
+ this.name = "";
+ this.location = "";
+ this.description = "";
+ this.collected = false;
+ }
+
+ // ======================= Methods ========================
+
+ /**
+ * Gets the type name.
+ *
+ * @return Returns the name of the type.
+ */
+ public String getTypeName() {
+ return getPowerUpName(type);
+ }
+ /**
+ * Gets the type color used for the marker on the mini map.
+ *
+ * @return Returns the mini map marker color.
+ */
+ public Color getTypeColor() {
+ switch (type) {
+ /* Global Power Ups */
+ case SUIT_EXPANSION: return new Color(255, 233, 0);
+ case MISSILE_EXPANSION: return new Color(255, 127, 39);
+ case ENERGY_TANK: return new Color(102, 232, 255);
+ case POWER_BOMB: return new Color(154, 58, 156);
+
+ /* Metroid Prime 1 */
+ case ARTIFACT: return new Color(188, 176, 95);
+
+ /* Metroid Prime 2 */
+ case BEAM_AMMO_EXPANSION: return new Color(157, 2, 251);
+ case TEMPLE_KEY: return new Color(243, 82, 82);
+ case SKY_TEMPLE_KEY: return new Color(96, 204, 201);
+
+ /* Metroid Prime 3 */
+ case SHIP_MISSILE_EXPANSION: return new Color(32, 220, 5);
+ case ENERGY_CELL: return new Color(36, 217, 208);
+ case RED_PHAZOID: return new Color(255, 74, 74);
+ }
+ return null;
+ }
+
+ // ==================== Static Methods ====================
+
+ /**
+ * Tests whether the power up is in the specified game.
+ *
+ * @param type - The power up type.
+ * @param game - The game to check with.
+ * @return Returns true if the power up type is in the game.
+ */
+ public static boolean isPowerUpInGame(int type, int game) {
+ switch (type) {
+ /* Global Power Ups */
+ case SUIT_EXPANSION: return true;
+ case MISSILE_EXPANSION: return true;
+ case ENERGY_TANK: return true;
+ case POWER_BOMB: return (game == 1 || game == 2);
+
+ /* Metroid Prime 1 */
+ case ARTIFACT: return (game == 1);
+
+ /* Metroid Prime 2 */
+ case BEAM_AMMO_EXPANSION: return (game == 2);
+ case TEMPLE_KEY: return (game == 2);
+ case SKY_TEMPLE_KEY: return (game == 2);
+
+ /* Metroid Prime 3 */
+ case SHIP_MISSILE_EXPANSION: return (game == 3);
+ case ENERGY_CELL: return (game == 3);
+ case RED_PHAZOID: return (game == 3);
+ }
+ return false;
+ }
+ /**
+ * Gets the image icon for the power up type.
+ *
+ * @param type - The power up type.
+ * @return Returns the image of the power up type.
+ */
+ public static Image getPowerUpIcon(int type) {
+ switch (type) {
+ /* Global Power Ups */
+ case SUIT_EXPANSION: return ImageLoader.getImage("suit_expansion");
+ case MISSILE_EXPANSION: return ImageLoader.getImage("missile_expansion");
+ case ENERGY_TANK: return ImageLoader.getImage("energy_tank");
+ case POWER_BOMB: return ImageLoader.getImage("power_bomb");
+
+ /* Metroid Prime 1 */
+ case ARTIFACT: return ImageLoader.getImage("artifact");
+
+ /* Metroid Prime 2 */
+ case BEAM_AMMO_EXPANSION: return ImageLoader.getImage("beam_ammo_expansion");
+ case TEMPLE_KEY: return ImageLoader.getImage("dark_temple_key");
+ case SKY_TEMPLE_KEY: return ImageLoader.getImage("sky_temple_key");
+
+ /* Metroid Prime 3 */
+ case SHIP_MISSILE_EXPANSION: return ImageLoader.getImage("ship_missile_expansion");
+ case ENERGY_CELL: return ImageLoader.getImage("energy_cell");
+ case RED_PHAZOID: return ImageLoader.getImage("red_phazoid");
+ }
+ return null;
+ }
+ /**
+ * Gets the raw name for the power up type.
+ *
+ * @param type - The power up type.
+ * @return Returns the raw name of the power up type.
+ */
+ public static String getPowerUpRawName(int type) {
+ switch (type) {
+ /* Global Power Ups */
+ case SUIT_EXPANSION: return "suit_expansions";
+ case MISSILE_EXPANSION: return "missile_expansions";
+ case ENERGY_TANK: return "energy_tanks";
+ case POWER_BOMB: return "power_bombs";
+
+ /* Metroid Prime 1 */
+ case ARTIFACT: return "artifacts";
+
+ /* Metroid Prime 2 */
+ case BEAM_AMMO_EXPANSION: return "beam_ammo_expansions";
+ case TEMPLE_KEY: return "dark_temple_keys";
+ case SKY_TEMPLE_KEY: return "sky_temple_keys";
+
+ /* Metroid Prime 3 */
+ case SHIP_MISSILE_EXPANSION: return "ship_missile_expansions";
+ case ENERGY_CELL: return "energy_cells";
+ case RED_PHAZOID: return "red_phazoids";
+ }
+ return "";
+ }
+ /**
+ * Gets the name for the power up type.
+ *
+ * @param type - The power up type.
+ * @return Returns the name of the power up type.
+ */
+ public static String getPowerUpName(int type) {
+ switch (type) {
+ /* Global Power Ups */
+ case SUIT_EXPANSION: return "Suit Expansion";
+ case MISSILE_EXPANSION: return "Missile Expansion";
+ case ENERGY_TANK: return "Energy Tank";
+ case POWER_BOMB: return "Power Bomb";
+
+ /* Metroid Prime 1 */
+ case ARTIFACT: return "Artifact";
+
+ /* Metroid Prime 2 */
+ case BEAM_AMMO_EXPANSION: return "Beam Ammo Expansion";
+ case TEMPLE_KEY: return "Dark Temple Key";
+ case SKY_TEMPLE_KEY: return "Sky Temple Key";
+
+ /* Metroid Prime 3 */
+ case SHIP_MISSILE_EXPANSION: return "Ship Missile Expansion";
+ case ENERGY_CELL: return "Energy Cell";
+ case RED_PHAZOID: return "Red Phaazoid";
+ }
+ return "";
+ }
+}
diff --git a/MetroidMapGuardian/src/game/Profile.java b/MetroidMapGuardian/src/game/Profile.java
new file mode 100644
index 0000000..01545ad
--- /dev/null
+++ b/MetroidMapGuardian/src/game/Profile.java
@@ -0,0 +1,216 @@
+package game;
+
+import geometry.Vector;
+
+import java.util.ArrayList;
+
+import nbt.NBTElement;
+import nbt.NBTTagCompound;
+import nbt.NBTTagList;
+
+import main.Game;
+
+/**
+ *
+ * @author Robert Jordan
+ *
+ */
+public class Profile {
+
+ // ======================= Members ========================
+
+ public String profileName;
+
+ public int currentTrilogy;
+
+ public ArrayList trilogies;
+
+
+ // ===================== Constructors =====================
+
+ /**
+ *
+ */
+ public Profile() {
+ this.profileName = "";
+ this.currentTrilogy = 0;
+ this.trilogies = new ArrayList();
+ this.trilogies.add(new TrilogyInfo(1));
+ this.trilogies.add(new TrilogyInfo(2));
+ this.trilogies.add(new TrilogyInfo(3));
+ }
+
+ public Profile(String name) {
+ this.profileName = name;
+ this.currentTrilogy = 0;
+ this.trilogies = new ArrayList();
+ this.trilogies.add(new TrilogyInfo(1));
+ this.trilogies.add(new TrilogyInfo(2));
+ this.trilogies.add(new TrilogyInfo(3));
+ }
+ public Profile(String name, NBTTagCompound nbt) {
+ nbt = nbt.getCompound("MetroidProfileData");
+
+ this.profileName = name;
+ this.currentTrilogy = nbt.getByte("currentTrilogy");
+ this.trilogies = new ArrayList();
+ for (NBTElement tag : nbt.getList("trilogies").getTags()) {
+ TrilogyInfo t = new TrilogyInfo((NBTTagCompound)tag);
+ this.trilogies.add(t);
+ }
+ }
+ public Profile(GameInstance instance) {
+ this.profileName = instance.profileName;
+ this.currentTrilogy = instance.currentTrilogy;
+ this.trilogies = new ArrayList();
+ for (Trilogy t : instance.trilogies) {
+ this.trilogies.add(new TrilogyInfo(t));
+ }
+ }
+
+ // ======================= Methods ========================
+
+ public int getCompletionPercentage(int game) {
+ TrilogyInfo t = trilogies.get(game - 1);
+
+ int total = 0;
+ int collected = 0;
+
+ for (int i = 0; i < t.powerUpsCollected.size(); i++) {
+ for (int j = 0; j < t.powerUpsCollected.get(i).size(); j++) {
+ total++;
+ if (t.powerUpsCollected.get(i).get(j))
+ collected ++;
+ }
+ }
+ return (int)((double)collected / total * 100);
+ }
+
+ public void saveProfile() {
+ NBTTagCompound root = new NBTTagCompound("root");
+ NBTTagCompound nbt = new NBTTagCompound("MetroidProfileData");
+
+ nbt.setByte("currentTrilogy", (byte)currentTrilogy);
+ NBTTagList list = new NBTTagList("trilogies");
+ for (TrilogyInfo t : trilogies) {
+ NBTTagCompound tag = new NBTTagCompound();
+ tag.setByte("game", (byte)t.game);
+ tag.setInteger("currentMap", t.currentMap);
+
+ NBTTagList powerUps = new NBTTagList("powerUpsCollected");
+ for (int i = 0; i < t.powerUpsCollected.size(); i++) {
+ NBTTagList powerUpTypes = new NBTTagList();
+ for (int j = 0; j < t.powerUpsCollected.get(i).size(); j++) {
+ powerUpTypes.addBoolean(t.powerUpsCollected.get(i).get(j));
+ }
+ powerUps.addList(powerUpTypes);
+ }
+ tag.setList("powerUpsCollected", powerUps);
+
+ NBTTagList maps = new NBTTagList("maps");
+ for (int i = 0; i < t.mapPans.size(); i++) {
+ NBTTagCompound map = new NBTTagCompound();
+ map.setDouble("x", t.mapPans.get(i).x);
+ map.setDouble("y", t.mapPans.get(i).y);
+ map.setDouble("zoom", t.mapZooms.get(i));
+ maps.addCompound(map);
+ }
+ tag.setList("maps", maps);
+ list.addCompound(tag);
+ }
+ nbt.setList("trilogies", list);
+ root.setCompound("MetroidProfileData", nbt);
+
+ NBTElement.saveNBTCompound("profiles/" + profileName + ".dat", root);
+ }
+}
+
+/**
+ *
+ * @author Robert Jordan
+ *
+ */
+class TrilogyInfo {
+
+ // ======================= Members ========================
+
+ /** The collection of power up collected states. */
+ public ArrayList> powerUpsCollected;
+
+ public ArrayList mapPans;
+
+ public ArrayList mapZooms;
+
+ public int currentMap;
+
+ public int game;
+
+
+ // ===================== Constructors =====================
+
+ /**
+ *
+ */
+ public TrilogyInfo(int game) {
+ this.game = game;
+ this.currentMap = 0;
+ this.mapPans = new ArrayList();
+ this.mapZooms = new ArrayList();
+ this.powerUpsCollected = new ArrayList>();
+
+ Trilogy t = Game.instance.trilogies.get(game - 1);
+ for (int i = 0; i < t.powerUps.size(); i++) {
+ this.powerUpsCollected.add(new ArrayList());
+ for (int j = 0; j < t.powerUps.get(i).size(); j++) {
+ this.powerUpsCollected.get(i).add(false);
+ }
+ }
+ for (int i = 0; i < t.maps.size(); i++) {
+ this.mapPans.add(new Vector());
+ this.mapZooms.add(1.0);
+ }
+ }
+
+ public TrilogyInfo(NBTTagCompound nbt) {
+ this.game = nbt.getByte("game");
+ this.currentMap = nbt.getInteger("currentMap");
+ this.mapPans = new ArrayList();
+ this.mapZooms = new ArrayList();
+ this.powerUpsCollected = new ArrayList>();
+
+ Trilogy t = Game.instance.trilogies.get(game - 1);
+ for (int i = 0; i < t.powerUps.size(); i++) {
+ NBTTagList list = nbt.getList("powerUpsCollected").getList(i, new NBTTagList());
+ this.powerUpsCollected.add(new ArrayList());
+
+ for (int j = 0; j < t.powerUps.get(i).size(); j++) {
+ this.powerUpsCollected.get(i).add(list.getBoolean(j));
+ }
+ }
+ for (int i = 0; i < t.maps.size(); i++) {
+ NBTTagCompound map = nbt.getList("maps").getCompound(i, new NBTTagCompound());
+ this.mapPans.add(new Vector(map.getDouble("x"), map.getDouble("y")));
+ this.mapZooms.add(map.getDouble("zoom", 1.0));
+ }
+ }
+
+ public TrilogyInfo(Trilogy t) {
+ this.game = t.game;
+ this.currentMap = t.currentMap;
+ this.mapPans = new ArrayList();
+ this.mapZooms = new ArrayList();
+ this.powerUpsCollected = new ArrayList>();
+
+ for (int i = 0; i < t.powerUps.size(); i++) {
+ this.powerUpsCollected.add(new ArrayList());
+
+ for (int j = 0; j < t.powerUps.get(i).size(); j++) {
+ this.powerUpsCollected.get(i).add(t.powerUps.get(i).get(j).collected);
+ }
+ }
+ for (int i = 0; i < t.maps.size(); i++) {
+ this.mapPans.add(new Vector(t.maps.get(i).view.pan));
+ this.mapZooms.add(t.maps.get(i).view.zoom);
+ }
+ }
+}
diff --git a/MetroidMapGuardian/src/game/Trilogy.java b/MetroidMapGuardian/src/game/Trilogy.java
new file mode 100644
index 0000000..129d30b
--- /dev/null
+++ b/MetroidMapGuardian/src/game/Trilogy.java
@@ -0,0 +1,167 @@
+package game;
+
+import java.util.ArrayList;
+import java.util.Scanner;
+
+import main.ImageLoader;
+import nbt.NBTElement;
+import nbt.NBTTagCompound;
+
+import room.Map;
+
+/**
+ *
+ * @author Robert Jordan
+ *
+ */
+public class Trilogy {
+
+ // ================== Private Variables ===================
+
+
+ // =================== Public Variables ===================
+
+ public static final int METROID_PRIME = 1;
+ public static final int METROID_PRIME_ECHOES = 2;
+ public static final int METROID_PRIME_CORRUPTION = 3;
+
+ // ======================= Members ========================
+
+ /** The game instance that contains this trilogy. */
+ public GameInstance instance;
+ /** The list of maps for this trilogy. */
+ public ArrayList