package models; import com.fasterxml.jackson.databind.node.BooleanNode; import com.fasterxml.jackson.databind.node.JsonNodeFactory; import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.TextNode; import decorators.ScoreDecorator; import formatters.ScoreFormatter; import org.joda.time.DateTime; import play.db.ebean.Model; import javax.persistence.Entity; import javax.persistence.Lob; import javax.persistence.ManyToOne; import javax.persistence.Transient; import java.math.BigDecimal; import static java.text.MessageFormat.format; import static org.apache.commons.lang3.StringUtils.isNotBlank; @Entity public class Score extends BaseModel<Score> implements Comparable<Score> { public static Finder<Long, Score> finder = new Model.Finder(Long.class, Score.class); @ManyToOne public Game game; @ManyToOne public Player player; @ManyToOne public Stage stage; @ManyToOne public Mode mode; @ManyToOne public Difficulty difficulty; @ManyToOne public Ship ship; @ManyToOne public Platform platform; @Lob public String comment; public String photo; public String inp; public String replay; public BigDecimal value; public boolean onecc; public Integer progression; @Transient public Long gapWithPreviousScore; public Integer rank; public Score(Game game, Player player, Stage stage, Ship ship, Mode mode, Difficulty difficulty, String comment, Platform platform, BigDecimal value, String photo, String replay) { this.game = game; this.player = player; this.stage = stage; this.mode = mode; this.ship = ship; this.difficulty = difficulty; this.comment = comment; this.platform = platform; this.value = value; this.photo = photo; this.replay = replay; this.onecc = this.is1CC(); } public Score(Long id, Game game, Player player, Stage stage, Ship ship, Mode mode, Difficulty difficulty, String comment, Platform platform, BigDecimal value, String photo, String replay, Integer rank) { this(game, player, stage, ship, mode, difficulty, comment, platform, value, photo, replay); this.rank = rank; this.id = id; } public Score(Game game, Player player, Stage stage, Ship ship, Mode mode, Difficulty difficulty, String comment, Platform platform, BigDecimal value) { this.game = game; this.player = player; this.stage = stage; this.ship = ship; this.mode = mode; this.difficulty = difficulty; this.comment = comment; this.platform = platform; this.value = value; } public Score(BigDecimal value) { this.value = value; } public String formattedDate() { return getCreatedSince(); } public String formattedDateInFrench() { return getCreatedSinceInFrench(); } public String formattedValue() { if (mode != null && mode.isTimerScore()) { return ScoreFormatter.formatAsTime(value); } return ScoreFormatter.format(value); } public String formattedRank() { Integer value = rank; if (value == null) { value = 0; } int hundredRemainder = value % 100; int tenRemainder = value % 10; if (hundredRemainder - tenRemainder == 10) { return value + "th"; } switch (tenRemainder) { case 1: return value + "st"; case 2: return value + "nd"; case 3: return value + "rd"; default: return value + "th"; } } public String formattedRankInFrench() { if (rank == null) { return ""; } if (rank == 1) { return "1ère"; } return rank + "ème"; } @Override public String toString() { return formattedValue(); } @Override public int compareTo(Score score) { int i = score.value.compareTo(this.value); if (i == 0) { if (score.stage != null && this.stage != null) { return score.stage.id.compareTo(this.stage.id); } } return i; } @Override public boolean equals(Object o) { return value.equals(((Score) o).value); } boolean isWorstThan(Score score) { if (isComparableWith(score)) { if (isNumericScore(score)) { return score.compareTo(this) < 0; } return score.compareTo(this) > 0; } return false; } private boolean isNumericScore(Score score) { return score.mode == null || !score.mode.isTimerScore(); } private boolean isComparableWith(Score score) { return hasDifficulty(score.difficulty) && hasMode(score.mode) && hasGame(score.game); } public boolean hasDifficulty(Difficulty difficulty) { if (difficulty == null && this.difficulty == null) { return true; } if (difficulty == null) { return false; } if (this.difficulty == null) { return false; } return this.difficulty.equals(difficulty); } private boolean hasGame(Game game) { return this.game.equals(game); } public boolean hasMode(Mode mode) { if (mode == null && this.mode == null) { return true; } if (mode == null) { return false; } if (this.mode == null) { return false; } return this.mode.equals(mode); } public boolean isPlayedBy(Player player) { if (player == null) { return false; } return this.player.equals(player); } public String getGameTitle() { String title = game.title; if (mode != null) { title += " " + mode.name; } if (difficulty != null) { title += " " + difficulty.name; } return title; } public void updateRank(Integer rank) { this.rank = rank; } public String tweet() { return format("{3} - {1} pts - {4} - {2}{5} - {0} {6}", formattedRank(), formattedValue(), player.name, game.title, (modeName() + " " + difficultyName()).trim(), twitterAccount(), "hiscores.shmup.com/game/" + game.id + "/" + game.getEscapedTitle()); } private String twitterAccount() { if (player.twitter != null) { return " (" + player.twitter + ")"; } return ""; } public String difficultyName() { return difficulty == null ? "" : difficulty.name; } public String modeName() { return mode == null ? "" : mode.name; } public String shipName() { return ship == null ? "" : ship.name; } public void setRank(int rank) { this.rank = rank; } public boolean isVip() { return player.isVip(); } public boolean is1CC() { if (this.stage != null) { String stageName = this.stage.name.toLowerCase(); return stageName.contains("all") || stageName.startsWith("2-") || stageName.toLowerCase().startsWith("boss 2-") || stageName.startsWith("3-") || stageName.toLowerCase().startsWith("boss 3-") || stageName.startsWith("4-") || stageName.toLowerCase().startsWith("boss 4-") || stageName.startsWith("5-") || stageName.toLowerCase().startsWith("boss 5-") || stageName.startsWith("6-") || stageName.toLowerCase().startsWith("boss 6-") || stageName.toUpperCase().contains("ENDLESS"); } return false; } public ScoreDecorator decorator() { return new ScoreDecorator(this); } public Integer getOpponentCount() { return finder.where().eq("game", game).eq("difficulty", difficulty).eq("mode", mode).gt("rank", 0).findRowCount(); } public Integer minutes() { if (isTimeScore()) { return new DateTime(this.value.longValue()).getMinuteOfHour(); } return null; } public Integer seconds() { if (isTimeScore()) { return new DateTime(this.value.longValue()).getSecondOfMinute(); } return null; } public Integer milliseconds() { if (isTimeScore()) { return new DateTime(this.value.longValue()).getMillisOfSecond(); } return null; } public BigDecimal valuePoints() { if (isTimeScore()) { return null; } return this.value; } public boolean isTimeScore() { return this.mode != null && this.mode.isTimerScore(); } public ObjectNode json() { ObjectNode scoreNode = new ObjectNode(JsonNodeFactory.instance); scoreNode.set("player", player.json()); scoreNode.set("game", game.json()); scoreNode.set("platform", platform.json()); if (mode != null) { scoreNode.set("mode", mode.json()); } scoreNode.set("stage", stage.json()); if (ship != null) { scoreNode.set("ship", ship.json()); } if (difficulty != null) { scoreNode.set("difficulty", difficulty.json()); } scoreNode.set("value", new TextNode(formattedValue())); scoreNode.set("rank", new TextNode(formattedRank())); if (onecc) { scoreNode.set("1cc", BooleanNode.TRUE); } scoreNode.set("date", new TextNode(formattedDateInFrench())); if (replay != null && isNotBlank(replay)) { scoreNode.set("replay", new TextNode(replay)); } if (photo != null && isNotBlank(photo)) { scoreNode.set("photo", new TextNode(photo)); } return scoreNode; } }