package com.kartoflane.superluminal2.ftl;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.TreeSet;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import com.kartoflane.superluminal2.components.enums.BoardingStrategies;
import com.kartoflane.superluminal2.components.enums.Images;
import com.kartoflane.superluminal2.components.enums.PlayerShipBlueprints;
import com.kartoflane.superluminal2.components.enums.Races;
import com.kartoflane.superluminal2.components.enums.Systems;
import com.kartoflane.superluminal2.core.Database;
import com.kartoflane.superluminal2.mvc.controllers.AbstractController;
import com.kartoflane.superluminal2.mvc.controllers.RoomController;
import com.kartoflane.superluminal2.utils.Utils;
public class ShipObject extends GameObject {
private boolean isPlayer = false;
private String blueprintName = PlayerShipBlueprints.HARD.toString();
private String layout = "myship";
private String img = "myship";
private String shipClass = "Ship Class";
private String shipName = "The Nameless One";
private String shipDescription = "This ship is completely devoid of any description whatsoever!";
private TreeSet<RoomObject> rooms;
private HashSet<DoorObject> doors;
private TreeSet<MountObject> mounts;
private TreeSet<GibObject> gibs;
private HashMap<Systems, ArrayList<SystemObject>> systemMap;
private HashMap<Images, ImageObject> imageMap;
private ArrayList<Races> crewList;
private HashMap<Races, Integer> crewMinMap;
private HashMap<Races, Integer> crewMaxMap;
private ArrayList<AugmentObject> augments;
private ArrayList<WeaponObject> weapons;
private ArrayList<DroneObject> drones;
private boolean weaponByList = false;
private boolean droneByList = false;
private WeaponList weaponList = Database.DEFAULT_WEAPON_LIST;
private DroneList droneList = Database.DEFAULT_DRONE_LIST;
private BoardingStrategies boardingAI = BoardingStrategies.SABOTAGE;
private int xOffset = 0;
private int yOffset = 0;
private int horizontal = 0;
private int vertical = 0;
private Rectangle ellipse = new Rectangle(0, 0, 150, 150);
private Point hullOffset = new Point(0, 0);
private Point hullSize = new Point(0, 0);
private Point cloakOffset = new Point(0, 0);
private Point floorOffset = new Point(0, 0);
private int weaponSlots = 0;
private int droneSlots = 0;
private int missiles = 0;
private int droneParts = 0;
private int hullHealth = 0;
private int maxPower = 0;
private int minSector = 1;
private int maxSector = 8;
private ShipObject() {
setDeletable(false);
rooms = new TreeSet<RoomObject>();
doors = new HashSet<DoorObject>();
mounts = new TreeSet<MountObject>();
gibs = new TreeSet<GibObject>();
systemMap = new HashMap<Systems, ArrayList<SystemObject>>();
imageMap = new HashMap<Images, ImageObject>();
augments = new ArrayList<AugmentObject>();
crewList = new ArrayList<Races>();
crewMinMap = new HashMap<Races, Integer>();
crewMaxMap = new HashMap<Races, Integer>();
weapons = new ArrayList<WeaponObject>();
drones = new ArrayList<DroneObject>();
for (int i = 0; i < 8; i++) {
weapons.add(Database.DEFAULT_WEAPON_OBJ);
drones.add(Database.DEFAULT_DRONE_OBJ);
}
for (int i = 0; i < 3; i++) {
augments.add(Database.DEFAULT_AUGMENT_OBJ);
}
for (Images image : Images.values()) {
ImageObject object = new ImageObject();
object.setAlias(image.name().toLowerCase());
imageMap.put(image, object);
}
for (Races race : Races.getRaces()) {
crewMinMap.put(race, 0);
crewMaxMap.put(race, 0);
}
for (int i = 0; i < 8; i++)
crewList.add(Races.NO_CREW);
}
public ShipObject(boolean isPlayer) {
this();
this.isPlayer = isPlayer;
for (Systems system : Systems.values()) {
ArrayList<SystemObject> list = new ArrayList<SystemObject>();
systemMap.put(system, list);
add(new SystemObject(system, this));
}
if (!isPlayer) {
ImageObject shieldObject = imageMap.get(Images.SHIELD);
shieldObject.setImagePath("db:img/ship/enemy_shields.png");
blueprintName = "NEW_ENEMY_SHIP";
weaponByList = true;
droneByList = true;
}
}
public void update() {
// Nothing to do here
}
public boolean isPlayerShip() {
return isPlayer;
}
public void setBlueprintName(String name) {
if (blueprintName == null)
throw new IllegalArgumentException("Blueprint name must not be null.");
blueprintName = name;
}
public String getBlueprintName() {
return blueprintName;
}
/**
* Sets the ship layout's namespace ('layout' attribute)
*/
public void setLayout(String layout) {
if (layout == null)
throw new IllegalArgumentException("Layout namespace must not be null.");
this.layout = layout;
}
/**
* @return ship layout's namespace ('layout' attribute)
*/
public String getLayout() {
return layout;
}
/**
* @return dat-relative path to the ship's TXT layout file.
*/
public String getLayoutTXT() {
return "data/" + layout + ".txt";
}
/**
* @return dat-relative path to the ship's XML layout file.
*/
public String getLayoutXML() {
return "data/" + layout + ".xml";
}
/**
* Sets the image namespace of the ship ('img' attribute)
*/
public void setImageNamespace(String image) {
if (image == null)
throw new IllegalArgumentException("Image namespace must not be null.");
img = image;
}
/**
* @return the image namespace of the ship ('img' attribute)
*/
public String getImageNamespace() {
return img;
}
/**
* Sets the name of the ship's class, eg. "Kestrel Cruiser", "Auto-Scout"
*/
public void setShipClass(String className) {
if (className == null)
throw new IllegalArgumentException("The ship class' name must not be null.");
shipClass = className;
}
/**
* @return name of the ship's class, eg. "Kestrel Cruiser", "Auto-Scout"
*/
public String getShipClass() {
return shipClass;
}
/**
* Sets the name of the ship, eg. "The Torus", "Gila Monster", etc.<br>
* Player ships only.
*/
public void setShipName(String shipName) {
if (shipName == null)
throw new IllegalArgumentException("The ship's name must not be null.");
this.shipName = shipName;
}
/**
* @return the name of the ship, eg. "The Torus", "Gila Monster", etc.
*/
public String getShipName() {
return shipName;
}
/**
* Sets the ship's description.<br>
* Player ships only.
*/
public void setShipDescription(String desc) {
if (desc == null)
throw new IllegalArgumentException("Description must not be null.");
shipDescription = desc;
}
/**
* @return the ship's description.
*/
public String getShipDescription() {
return shipDescription;
}
/**
* Sets the X offset of the ship's origin, in grid cells.
*/
public void setXOffset(int i) {
xOffset = i;
}
/**
* @return grid cell component of the ship origin's offset on the X axis (X_OFFSET property)
*/
public int getXOffset() {
return xOffset;
}
/**
* Sets the Y offset of the ship's origin, in grid cells.
*/
public void setYOffset(int i) {
yOffset = i;
}
/**
* @return grid cell component of the ship origin's offset on the Y axis (Y_OFFSET property)
*/
public int getYOffset() {
return yOffset;
}
public Point getOffsetThick() {
return new Point(xOffset, yOffset);
}
/**
* Sets the X offset of the ship's origin, in pixels.
*/
public void setHorizontal(int i) {
horizontal = i;
}
/**
* @return pixel component of the ship origin's offset on the X axis (HORIZONTAL property)
*/
public int getHorizontal() {
return horizontal;
}
/**
* Sets the Y offset of the ship's origin, in pixels.
*/
public void setVertical(int i) {
vertical = i;
}
/**
* @return pixel component of the ship origin's offset on the Y axis (VERTICAL property)
*/
public int getVertical() {
return vertical;
}
public Point getOffsetFine() {
return new Point(horizontal, vertical);
}
/**
* Sets the dimensions of the shield image.
*
* @see {@link #setEllipse(int, int, int, int)}
*/
public void setEllipse(Rectangle rect) {
if (rect == null)
throw new IllegalArgumentException("Ellipse must not be null");
setEllipse(rect.x, rect.y, rect.width, rect.height);
}
/**
* Sets the dimensions of the shield image.
*
* @param xOff
* offset from the ship's center
* @param yOff
* offset from the ship's center
* @param width
* half of the image's width
* @param height
* half of the image's height
*/
public void setEllipse(int xOff, int yOff, int width, int height) {
ellipse.x = xOff;
ellipse.y = yOff;
ellipse.width = width;
ellipse.height = height;
}
public void setEllipseX(int x) {
ellipse.x = x;
}
public void setEllipseY(int y) {
ellipse.y = y;
}
public void setEllipseWidth(int w) {
ellipse.width = w;
}
public void setEllipseHeight(int h) {
ellipse.height = h;
}
/**
* @return dimensions of the shield image.<br>
* X and Y values represent offset from the ship's center (center of
* smallest rectangle containing all rooms)<br>
* Width and height are half of the actual image's size.
*/
public Rectangle getEllipse() {
return Utils.copy(ellipse);
}
public int getEllipseX() {
return ellipse.x;
}
public int getEllipseY() {
return ellipse.y;
}
public int getEllipseWidth() {
return ellipse.width;
}
public int getEllipseHeight() {
return ellipse.height;
}
/**
* Sets the dimensions of the hull image.
*
* @see {@link #setHullDimensions(int, int, int, int)}
*/
public void setHullDimensions(Rectangle rect) {
if (rect == null)
throw new IllegalArgumentException("Hull dimensions must not be null");
setHullDimensions(rect.x, rect.y, rect.width, rect.height);
}
/**
* Sets the dimensions of the hull image.
*
* @param x
* offset from the ship's origin
* @param y
* offset from the ship's origin
* @param w
* width of the image
* @param h
* height of the image
*/
public void setHullDimensions(int x, int y, int w, int h) {
hullOffset.x = x;
hullOffset.y = y;
hullSize.x = w;
hullSize.y = h;
}
/**
* @return dimensions of the hull image.<br>
* X and Y values represent the hull's offset from the ship's origin.
*/
public Rectangle getHullDimensions() {
return new Rectangle(hullOffset.x, hullOffset.y, hullSize.x, hullSize.y);
}
/**
* @return offset of the hull image from the ship's origin.
*/
public Point getHullOffset() {
return Utils.copy(hullOffset);
}
public Point getHullSize() {
return Utils.copy(hullSize);
}
/**
* Sets the offset of the cloak image from the top-left corner of the hull image.
*/
public void setCloakOffset(Point p) {
setCloakOffset(p.x, p.y);
}
/**
* Sets the offset of the cloak image from the top-left corner of the hull image.
*/
public void setCloakOffset(int x, int y) {
cloakOffset.x = x;
cloakOffset.y = y;
}
/**
* @return the offset of the cloak image from the top-left corner of the hull image.
*/
public Point getCloakOffset() {
return Utils.copy(cloakOffset);
}
/**
* Sets the offset of the floor image from the top-left corner of the hull image.
*/
public void setFloorOffset(Point p) {
setFloorOffset(p.x, p.y);
}
/**
* Sets the offset of the floor image from the top-left corner of the hull image.
*/
public void setFloorOffset(int x, int y) {
floorOffset.x = x;
floorOffset.y = y;
}
/**
* @return the offset of the floor image from the top-left corner of the hull image.
*/
public Point getFloorOffset() {
return Utils.copy(floorOffset);
}
/**
* @return the first system object associated with the given system type.
*/
public SystemObject getSystem(Systems sys) {
if (sys == null)
throw new IllegalArgumentException("System type must not be null.");
return systemMap.get(sys).get(0);
}
public ArrayList<SystemObject> getSystems(Systems sys) {
if (sys == null)
throw new IllegalArgumentException("System type must not be null.");
return systemMap.get(sys);
}
/**
* @return image object associated with the given image type.
*/
public ImageObject getImage(Images image) {
if (image == null)
throw new IllegalArgumentException("Image type must not be null.");
return imageMap.get(image);
}
/**
* Sets the image used by the given image type.
*/
public void setImage(Images image, String path) {
if (image == null)
throw new IllegalArgumentException("Image type must not be null.");
imageMap.get(image).setImagePath(path);
}
public void setHealth(int hp) {
if (hp < 0)
throw new IllegalArgumentException("Amount of health points must be non-negative.");
hullHealth = hp;
}
public int getHealth() {
return hullHealth;
}
/**
* Sets the amount of power bars available to the ship at the start of the game.
*/
public void setPower(int power) {
if (power < 0)
throw new IllegalArgumentException("Power must be non-negative.");
maxPower = power;
}
/**
* @return the amount of power bars available to the ship at the start of the game.
*/
public int getPower() {
return maxPower;
}
/**
* Sets the number of weapon slots that the ship has.<br>
* This determines how many weapons the ship can have active at once.
*/
public void setWeaponSlots(int slots) {
if (slots < 0)
throw new IllegalArgumentException("Number of slots must be non-negative.");
weaponSlots = slots;
if (weapons.size() > slots) {
for (int i = slots; i < weapons.size(); i++)
weapons.remove(i);
} else if (weapons.size() < slots) {
for (int i = weapons.size(); i <= slots; i++)
weapons.add(Database.DEFAULT_WEAPON_OBJ);
}
}
/**
* @return the number of weapon slots that the ship has
*/
public int getWeaponSlots() {
return weaponSlots;
}
public boolean getWeaponsByList() {
return weaponByList;
}
public void setWeaponsByList(boolean byList) {
weaponByList = byList;
}
/**
* Sets the weapon list that the ship will use as its loadout.<br>
* Enemy ships only.
*/
public void setWeaponList(WeaponList list) {
if (isPlayer)
throw new IllegalStateException("Not an enemy ship.");
if (list == null)
throw new IllegalArgumentException("List must not be null.");
weaponList = list;
}
/**
* @return the weapon list that the ship uses as its loadout
*/
public WeaponList getWeaponList() {
return weaponList;
}
public WeaponObject[] getWeapons() {
return weapons.toArray(new WeaponObject[0]);
}
/**
* Puts the new weapon at the specified index in the weapon list.
*/
public void changeWeapon(int index, WeaponObject neu) {
if (index < 0 || index > weaponSlots)
throw new IllegalArgumentException("Index is out of bounds: " + index);
if (neu == null)
throw new IllegalArgumentException("New weapon must not be null.");
weapons.set(index, neu);
coalesceWeapons();
}
/**
* Removes the first occurence of the old weapon, and puts the new weapon in its place.
*
* @return index at which the new weapon was placed
*/
public int changeWeapon(WeaponObject old, WeaponObject neu) {
if (old == null)
throw new IllegalArgumentException("Old weapon must not be null.");
if (neu == null)
throw new IllegalArgumentException("New weapon must not be null.");
int i = weapons.indexOf(old);
if (i == -1)
throw new IllegalArgumentException("Old weapon not found.");
weapons.set(i, neu);
return i;
}
/**
* Coalesces the weapons, moving all dummy weapons to the end of the list, so that
* there are no gaps between 'real' weapons.
*/
private void coalesceWeapons() {
for (int i = 0; i < weapons.size(); i++) {
WeaponObject weapon = weapons.get(i);
if (weapon == Database.DEFAULT_WEAPON_OBJ) {
weapons.remove(weapon);
weapons.add(weapon);
}
}
}
/**
* Sets the number of drone slots that the ship has.<br>
* This determines how many drones the ship can have active at once.
*/
public void setDroneSlots(int slots) {
if (slots < 0)
throw new IllegalArgumentException("Number of slots must be non-negative.");
droneSlots = slots;
}
/**
* @return the number of drone slots that the ship has
*/
public int getDroneSlots() {
return droneSlots;
}
public boolean getDronesByList() {
return droneByList;
}
public void setDronesByList(boolean byList) {
droneByList = byList;
}
/**
* Sets the drone list that the ship will use as its loadout.<br>
* Enemy ships only.
*/
public void setDroneList(DroneList list) {
if (isPlayer)
throw new IllegalStateException("Not an enemy ship.");
if (list == null)
throw new IllegalArgumentException("List must not be null.");
droneList = list;
}
/**
* @return the drone list that the ship uses as its loadout
*/
public DroneList getDroneList() {
return droneList;
}
public DroneObject[] getDrones() {
return drones.toArray(new DroneObject[0]);
}
/**
* Puts the new drone at the specified index in the drone list.
*/
public void changeDrone(int index, DroneObject neu) {
if (index < 0 || index > droneSlots)
throw new IllegalArgumentException("Index is out of bounds: " + index);
if (neu == null)
throw new IllegalArgumentException("New drone must not be null.");
drones.set(index, neu);
coalesceDrones();
}
/**
* Removes the first occurence of the old drone, and puts the new drone in its place.
*
* @return index at which the new drone was placed
*/
public int changeDrone(DroneObject old, DroneObject neu) {
if (old == null)
throw new IllegalArgumentException("Old drone must not be null.");
if (neu == null)
throw new IllegalArgumentException("New drone must not be null.");
int i = drones.indexOf(old);
if (i == -1)
throw new IllegalArgumentException("Old drone not found.");
drones.set(i, neu);
return i;
}
/**
* Coalesces drones, moving all dummy drones to the end of the list, so that
* there are no gaps between 'real' drones.
*/
private void coalesceDrones() {
for (int i = 0; i < drones.size(); i++) {
DroneObject drone = drones.get(i);
if (drone == Database.DEFAULT_DRONE_OBJ) {
drones.remove(drone);
drones.add(drone);
}
}
}
public void setMissilesAmount(int amount) {
if (amount < 0)
throw new IllegalArgumentException("Amount must be non-negative.");
missiles = amount;
}
public int getMissilesAmount() {
return missiles;
}
public void setDronePartsAmount(int amount) {
if (amount < 0)
throw new IllegalArgumentException("Amount must be non-negative.");
droneParts = amount;
}
public int getDronePartsAmount() {
return droneParts;
}
/**
* Sets the minimum sector in which the ship can appear, inclusive (?)<br>
* Enemy ships only.
*/
public void setMinSector(int min) {
if (min < 1 || min > 8)
throw new IllegalArgumentException("Sector number must be within 1..8 range, inclusive: " + min);
minSector = min;
}
/**
* Enemy ships only.
*
* @return the minimum sector in which the ship can appear, inclusive (?)
*/
public int getMinSector() {
return minSector;
}
/**
* Sets the maximum sector in which the ship can appear, inclusive (?)<br>
* Enemy ships only.
*/
public void setMaxSector(int max) {
if (max < 1 || max > 8)
throw new IllegalArgumentException("Sector number must be within 1..8 range, inclusive: " + max);
maxSector = max;
}
/**
* Enemy ships only.
*
* @return the maximum sector in which the ship can appear, inclusive (?)
*/
public int getMaxSector() {
return maxSector;
}
/**
* Sets the boarding strategy that the ship's crew is going to use when boarding.<br>
* Enemy ships only.
*/
public void setBoardingAI(BoardingStrategies ai) {
if (ai == null)
throw new IllegalArgumentException("Boarding AI must not be null.");
boardingAI = ai;
}
/**
* Enemy ships only.
*
* @return the boarding strategy that the ship's crew is going to use when boarding.
*/
public BoardingStrategies getBoardingAI() {
return boardingAI;
}
/**
* Puts the new race at the specified index in the race list.<br>
* Player ships only.
*/
public void changeCrew(int index, Races neu) {
if (neu == null)
throw new IllegalArgumentException("New augment must not be null.");
if (index < 0 || index > 7)
throw new IllegalArgumentException("Index is out of bounds: " + index);
crewList.set(index, neu);
coalesceCrew();
}
/**
* Removes the first occurence of the old race, and puts the new race in its place.<br>
* Player ships only.
*
* @return index at which the new race was placed
*/
public int changeCrew(Races old, Races neu) {
if (old == null)
throw new IllegalArgumentException("Old augment must not be null.");
if (neu == null)
throw new IllegalArgumentException("New augment must not be null.");
int i = crewList.indexOf(old);
if (i == -1)
throw new IllegalArgumentException("Old crew not found.");
crewList.set(i, neu);
return i;
}
/**
* @return the number of crew members of the given race in the ship.
*/
public int getCrewCount(Races r) {
int result = 0;
for (Races race : crewList) {
if (race == r)
result++;
}
return result;
}
public Races[] getCrew() {
return crewList.toArray(new Races[0]);
}
/**
* Coalesces the crew list, moving all null entries to the end of the list, so that
* there are no gaps between real crew members.
*/
private void coalesceCrew() {
for (int i = 0; i < crewList.size(); i++) {
Races crew = crewList.get(i);
if (crew == Races.NO_CREW) {
crewList.remove(crew);
crewList.add(crew);
}
}
}
/**
* Sets the minimum amount of crew members of the given race that the ship can have.<br>
* Enemy ships only.
*/
public void setCrewMin(Races race, int amount) {
if (race == null)
throw new IllegalArgumentException("Race must not be null.");
if (amount < 0)
throw new IllegalArgumentException("Amount must be non-negative.");
crewMinMap.put(race, amount);
}
/**
* Enemy ships only.
*
* @return minimum amount of crew members of the given race that the ship can have
*/
public int getCrewMin(Races race) {
if (race == null)
throw new IllegalArgumentException("Race must not be null.");
Integer result = crewMinMap.get(race);
return result == null ? 0 : result;
}
/**
* Sets the maximum amount of crew members of the given race that the ship can have.<br>
* Enemy ships only.
*/
public void setCrewMax(Races race, int amount) {
if (race == null)
throw new IllegalArgumentException("Race must not be null.");
if (amount < 0)
throw new IllegalArgumentException("Amount must be non-negative.");
crewMaxMap.put(race, amount);
}
/**
* Enemy ships only.
*
* @return maximum amount of crew members of the given race that the ship can have
*/
public int getCrewMax(Races race) {
if (race == null)
throw new IllegalArgumentException("Race must not be null.");
Integer result = crewMaxMap.get(race);
return result == null ? 0 : result;
}
/**
* Modifying the array doesn't change the order of elements in the ship.
*
* @return an array of all augments in this ship
*/
public AugmentObject[] getAugments() {
return augments.toArray(new AugmentObject[0]);
}
/**
* Puts the new augment at the specified index in the augment list.
*/
public void changeAugment(int index, AugmentObject neu) {
if (index < 0 || index > 2)
throw new IllegalArgumentException("Index is out of bounds: " + index);
if (neu == null)
throw new IllegalArgumentException("New augment must not be null.");
augments.set(index, neu);
coalesceAugments();
}
/**
* Removes the first occurence of the old augment, and puts the new augment in its place.
*
* @return index at which the new augment was placed
*/
public int changeAugment(AugmentObject old, AugmentObject neu) {
if (old == null)
throw new IllegalArgumentException("Old augment must not be null.");
if (neu == null)
throw new IllegalArgumentException("New augment must not be null.");
int i = augments.indexOf(old);
if (i == -1)
throw new IllegalArgumentException("Old augment not found.");
augments.set(i, neu);
return i;
}
/**
* Coalesces augments, moving all dummy augments to the end of the list, so that
* there are no gaps between 'real' augments.
*/
private void coalesceAugments() {
for (int i = 0; i < augments.size(); i++) {
AugmentObject augment = augments.get(i);
if (augment == Database.DEFAULT_AUGMENT_OBJ) {
augments.remove(augment);
augments.add(augment);
}
}
}
/**
* Modifying the array doesn't change the order of elements in the ship.
*
* @return an array of all rooms in this ship
*/
public RoomObject[] getRooms() {
return rooms.toArray(new RoomObject[0]);
}
/**
* Modifying the array doesn't change the order of elements in the ship.
*
* @return an array of all doors in this ship
*/
public DoorObject[] getDoors() {
return doors.toArray(new DoorObject[0]);
}
/**
* Modifying the array doesn't change the order of elements in the ship.
*
* @return an array of all mounts in this ship
*/
public MountObject[] getMounts() {
return mounts.toArray(new MountObject[0]);
}
/**
* Modifying the array doesn't change the order of elements in the ship.
*
* @return an array of all gibs in this ship
*/
public GibObject[] getGibs() {
return gibs.toArray(new GibObject[0]);
}
/**
* @param id
* ID number of the sought room
* @return room with the given ID, or null if none was found
*/
public RoomObject getRoomById(int id) {
if (id == -1)
return Database.AIRLOCK_OBJECT;
RoomObject[] roomz = getRooms();
try {
return roomz[binarySearch(roomz, id, 0, roomz.length)];
} catch (IndexOutOfBoundsException e) {
return null;
}
}
/**
* @param id
* ID number of the sought mount
* @return mount with the given ID, or null if none was found
*/
public MountObject getMountById(int id) {
for (MountObject mount : mounts) {
if (mount.getId() == id)
return mount;
}
return null;
}
/**
* @param id
* ID number of the sought gib
* @return gib with the given ID, or null if none was found
*/
public GibObject getGibById(int id) {
for (GibObject gib : gibs) {
if (gib.getId() == id)
return gib;
}
return null;
}
/**
* Adds the game object to the ship, storing it in the appropriate list
* depending on its type.<br>
* <br>
* This method should not be called directly.
* Use {@link com.kartoflane.superluminal2.ui.ShipContainer#add(AbstractController)
* ShipContainer.add()} instead
*
* @param object
* object that is to be added
*/
public void add(GameObject object) {
if (object == null)
throw new IllegalArgumentException("Object must not be null.");
if (object instanceof RoomObject) {
rooms.add((RoomObject) object);
} else if (object instanceof DoorObject) {
doors.add((DoorObject) object);
} else if (object instanceof MountObject) {
mounts.add((MountObject) object);
} else if (object instanceof GibObject) {
gibs.add((GibObject) object);
} else if (object instanceof AugmentObject) {
augments.add((AugmentObject) object);
} else if (object instanceof SystemObject) {
SystemObject system = (SystemObject) object;
systemMap.get(system.getSystemId()).add(system);
} else {
throw new IllegalArgumentException("Game object was of unexpected type: " + object.getClass().getSimpleName());
}
}
/**
* Removes the game object from the ship.<br>
* <br>
* This method should not be called directly.
* Use {@link com.kartoflane.superluminal2.ui.ShipContainer#remove(RoomController)
* ShipContainer.remove()} instead
*
* @param object
* object that is to be removed
*/
public void remove(GameObject object) {
if (object instanceof RoomObject) {
rooms.remove(object);
} else if (object instanceof DoorObject) {
doors.remove(object);
} else if (object instanceof MountObject) {
mounts.remove(object);
} else if (object instanceof GibObject) {
gibs.remove(object);
} else if (object instanceof AugmentObject) {
augments.remove(object);
} else if (object instanceof SystemObject) {
SystemObject system = (SystemObject) object;
systemMap.get(system.getSystemId()).remove(system);
} else {
throw new IllegalArgumentException("Game object was of unexpected type: " + object.getClass().getSimpleName());
}
}
/**
* Coalesces the rooms, removing gaps in room numbering.
*/
public void coalesceRooms() {
int id = 0;
RoomObject[] roomArray = getRooms();
rooms.clear();
for (RoomObject room : roomArray) {
room.setId(id++);
rooms.add(room);
}
}
/**
* Coalesces the gibs, removing gaps in gib numbering.
*/
public void coalesceGibs() {
// Gibs are 1-relative
int id = 1;
GibObject[] gibArray = getGibs();
gibs.clear();
for (GibObject gib : gibArray) {
gib.setId(id++);
gibs.add(gib);
}
}
public boolean hasOverlappingRooms() {
boolean result = false;
for (RoomObject r : rooms) {
Rectangle b = r.getBounds();
for (RoomObject o : rooms) {
if (r != o && b.intersects(o.getBounds())) {
result = true;
break;
}
}
}
return result;
}
/**
* Automatically links doors to adjacent rooms.
*/
public void linkDoors() {
for (DoorObject door : doors) {
door.verifyLinks();
if (door.isHorizontal()) {
if (door.getLeftRoom() == null)
door.setLeftRoom(getRoomAt(door.getX(), door.getY() - 1));
if (door.getRightRoom() == null)
door.setRightRoom(getRoomAt(door.getX(), door.getY()));
} else {
if (door.getLeftRoom() == null)
door.setLeftRoom(getRoomAt(door.getX() - 1, door.getY()));
if (door.getRightRoom() == null)
door.setRightRoom(getRoomAt(door.getX(), door.getY()));
}
// When linking to airlocks, the airlock has to be linked as the right "room"
if (door.getLeftRoom() == Database.AIRLOCK_OBJECT && door.getRightRoom() != Database.AIRLOCK_OBJECT) {
door.setLeftRoom(door.getRightRoom());
door.setRightRoom(Database.AIRLOCK_OBJECT);
}
}
}
/**
* Resets door links to null, so that they will be automatically linked.
*/
public void resetDoorLinks() {
for (DoorObject door : doors) {
door.setLeftRoom(null);
door.setRightRoom(null);
}
}
private RoomObject getRoomAt(int x, int y) {
for (RoomObject room : rooms) {
if (room.getBounds().contains(x, y))
return room;
}
return Database.AIRLOCK_OBJECT;
}
public void sort() {
// Reinsert all objects to sort the sets
Object[] array = rooms.toArray(new Object[0]);
for (Object o : array)
rooms.remove(o);
for (Object o : array)
rooms.add((RoomObject) o);
array = mounts.toArray(new Object[0]);
for (Object o : array)
mounts.remove(o);
for (Object o : array)
mounts.add((MountObject) o);
array = gibs.toArray(new Object[0]);
for (Object o : array)
gibs.remove(o);
for (Object o : array)
gibs.add((GibObject) o);
}
/**
* @return the next unused ID that can be assigned to a new room
*/
public int getNextRoomId() {
int id = 0;
for (RoomObject object : rooms) {
if (id == object.getId())
id++;
}
return id;
}
/**
* @return the next unused ID that can be assigned to a new mount
*/
public int getNextMountId() {
int id = 0;
for (MountObject object : mounts) {
if (id == object.getId())
id++;
}
return id;
}
private static int binarySearch(RoomObject[] array, int id, int min, int max) {
if (min > max)
return -1;
int mid = (min + max) / 2;
if (array[mid].getId() < id)
return binarySearch(array, id, mid + 1, max);
else if (array[mid].getId() > id)
return binarySearch(array, id, min, mid - 1);
else
return mid;
}
}