package seng302.model; import java.util.HashMap; import java.util.Observable; import java.util.Observer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import seng302.gameServer.GameState; import seng302.model.mark.Mark; import seng302.utilities.GeoUtility; /** * Yacht class for the racing boat.
Class created to store more variables (eg. boat statuses)
* compared to the XMLParser boat class, also done outside Boat class because some old variables are
* not used anymore.
*/
public class ServerYacht extends Observable {
private Logger logger = LoggerFactory.getLogger(ClientYacht.class);
public static final Double TURN_STEP = 5.0;
private String boatType;
private Integer sourceId;
private String hullID; //matches HullNum in the XML spec.
private String shortName;
private String boatName;
private String country;
private Double lastHeading;
private Boolean sailIn;
private Double heading;
private GeoPoint location;
private Double currentVelocity;
private Boolean isAuto;
private Double autoHeading;
private Integer currentMarkSeqID = 0;
private GeoPoint lastLocation;
private Boolean hasEnteredRoundingZone;
private Mark closestCurrentMark;
private Boolean hasPassedLine;
private Boolean hasPassedThroughGate;
private Boolean finishedRace;
public ServerYacht(String boatType, Integer sourceId, String hullID, String shortName,
String boatName, String country) {
this.boatType = boatType;
this.sourceId = sourceId;
this.hullID = hullID;
this.shortName = shortName;
this.boatName = boatName;
this.country = country;
this.sailIn = false;
this.isAuto = false;
this.location = new GeoPoint(57.670341, 11.826856);
this.lastLocation = location;
this.heading = 120.0; //In degrees
this.currentVelocity = 0d; //in mms-1
this.hasEnteredRoundingZone = false;
this.hasPassedLine = false;
this.hasPassedThroughGate = false;
this.finishedRace = false;
}
/**
* Changes the boats current currentVelocity by a set amount, positive or negative
*
* @param velocityChange The ammount to change the currentVelocity by, in mms-1
*/
public void changeVelocity(Double velocityChange) {
currentVelocity += velocityChange;
}
/**
* Updates the boat to a new GeoPoint whilst preserving the last location
*
* @param secondsElapsed The seconds elapsed since the last update of this yacht
*/
public void updateLocation(Double secondsElapsed) {
lastLocation = location;
location = GeoUtility.getGeoCoordinate(location, heading, currentVelocity * secondsElapsed);
}
/**
* Add ServerToClientThread as the observer, this observer pattern mainly server for the boat
* rounding package.
*/
@Override
public void addObserver(Observer o) {
super.addObserver(o);
}
/**
* Adjusts the heading of the boat by a given amount, while recording the boats last heading.
*
* @param amount the amount by which to adjust the boat heading.
*/
public void adjustHeading(Double amount) {
Double newVal = heading + amount;
lastHeading = heading;
heading = (double) Math.floorMod(newVal.longValue(), 360L);
}
/**
* Swaps the boats direction from one side of the wind to the other.
*/
public void tackGybe(Double windDirection) {
if (isAuto) {
disableAutoPilot();
} else {
Double normalizedHeading = normalizeHeading();
Double newVal = (-2 * normalizedHeading) + heading;
Double newHeading = (double) Math.floorMod(newVal.longValue(), 360L);
setAutoPilot(newHeading);
}
}
/**
* Enables the boats auto pilot feature, which will move the boat towards a given heading.
*
* @param thisHeading The heading to move the boat towards.
*/
private void setAutoPilot(Double thisHeading) {
isAuto = true;
autoHeading = thisHeading;
}
/**
* Disables the auto pilot function.
*/
public void disableAutoPilot() {
isAuto = false;
}
/**
* Moves the boat towards the given heading when the auto pilot was set. Disables the auto pilot
* in the event that the boat is within the range of 1 turn step of its goal.
*/
public void runAutoPilot() {
if (isAuto) {
turnTowardsHeading(autoHeading);
if (Math.abs(heading - autoHeading)
<= TURN_STEP) { //Cancel when within 1 turn step of target.
isAuto = false;
}
}
}
public void toggleSailIn() {
sailIn = !sailIn;
}
public void turnUpwind() {
disableAutoPilot();
Double normalizedHeading = normalizeHeading();
if (normalizedHeading == 0) {
if (lastHeading < 180) {
adjustHeading(-TURN_STEP);
} else {
adjustHeading(TURN_STEP);
}
} else if (normalizedHeading == 180) {
if (lastHeading < 180) {
adjustHeading(TURN_STEP);
} else {
adjustHeading(-TURN_STEP);
}
} else if (normalizedHeading < 180) {
adjustHeading(-TURN_STEP);
} else {
adjustHeading(TURN_STEP);
}
}
public void turnDownwind() {
disableAutoPilot();
Double normalizedHeading = normalizeHeading();
if (normalizedHeading == 0) {
if (lastHeading < 180) {
adjustHeading(TURN_STEP);
} else {
adjustHeading(-TURN_STEP);
}
} else if (normalizedHeading == 180) {
if (lastHeading < 180) {
adjustHeading(-TURN_STEP);
} else {
adjustHeading(TURN_STEP);
}
} else if (normalizedHeading < 180) {
adjustHeading(TURN_STEP);
} else {
adjustHeading(-TURN_STEP);
}
}
/**
* Takes the VMG from the polartable for upwind or downwind depending on the boats direction,
* and uses this to calculate a heading to move the yacht towards.
*/
public void turnToVMG() {
if (isAuto) {
disableAutoPilot();
} else {
Double normalizedHeading = normalizeHeading();
Double optimalHeading;
HashMap