package seng302.model; import javafx.scene.paint.Color; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import seng302.gameServer.GameState; import seng302.gameServer.messages.BoatStatus; import seng302.model.mark.Mark; import seng302.model.token.TokenType; import seng302.utilities.GeoUtility; import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; import java.util.HashMap; import java.util.Objects; import java.util.Observable; import java.util.Observer; import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; /** * 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 {
private Logger logger = LoggerFactory.getLogger(ServerYacht.class);
//Boat info
private BoatMeshType boatType;
private Double turnStep = 5.0;
private Double maxSpeedMultiplier = 1.0;
private Double acceleration = 1.0;
private Integer sourceId;
private String hullID; //matches HullNum in the XML spec.
private String shortName;
private String boatName;
private String country;
private BoatStatus boatStatus;
private Color boatColor;
//Location
private Double lastHeading;
private Boolean sailIn;
private Double heading;
private GeoPoint lastLocation;
private GeoPoint location;
private Double currentVelocity;
private Boolean isAuto;
private Double autoHeading;
private Integer legNumber;
//Mark Rounding
private Integer currentMarkSeqID;
private Boolean hasEnteredRoundingZone;
private Mark closestCurrentMark;
private Boolean hasPassedLine;
private Boolean hasPassedThroughGate;
//PowerUp
private TokenType powerUp;
private Long powerUpStartTime;
public ServerYacht(BoatMeshType boatType, Integer sourceId, String hullID, String shortName,
String boatName, String country) {
setBoatType(boatType);
this.boatStatus = BoatStatus.PRESTART;
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.67046, 11.83751);
this.lastLocation = location;
this.heading = 120.0; //In degrees
this.currentVelocity = 0d; //in mms-1
this.currentMarkSeqID = 0;
this.legNumber = 0;
this.boatColor = Colors.getColor(sourceId - 1);
this.powerUp = null;
this.hasEnteredRoundingZone = false;
this.hasPassedLine = false;
this.hasPassedThroughGate = 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);
}
public void setLocation(GeoPoint geoPoint) {
location = geoPoint;
}
public void powerUp(TokenType powerUp) {
this.powerUp = powerUp;
powerUpStartTime = System.currentTimeMillis();
}
public void powerDown() {
this.powerUp = null;
}
public Long getPowerUpStartTime() {
return powerUpStartTime;
}
public TokenType getPowerUp() {
return powerUp;
}
/**
* 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.
* @param windDirection .
*/
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)
<= turnStep) { //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(-turnStep);
} else {
adjustHeading(turnStep);
}
} else if (normalizedHeading == 180) {
if (lastHeading < 180) {
adjustHeading(turnStep);
} else {
adjustHeading(-turnStep);
}
} else if (normalizedHeading < 180) {
adjustHeading(-turnStep);
} else {
adjustHeading(turnStep);
}
}
public void turnDownwind() {
disableAutoPilot();
Double normalizedHeading = normalizeHeading();
if (normalizedHeading == 0) {
if (lastHeading < 180) {
adjustHeading(turnStep);
} else {
adjustHeading(-turnStep);
}
} else if (normalizedHeading == 180) {
if (lastHeading < 180) {
adjustHeading(-turnStep);
} else {
adjustHeading(turnStep);
}
} else if (normalizedHeading < 180) {
adjustHeading(turnStep);
} else {
adjustHeading(-turnStep);
}
}
/**
* 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