/** * Copyright (C) 2013 Gundog Studios LLC. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.godsandtowers.core; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.util.ArrayList; import java.util.Arrays; import com.godsandtowers.achievements.Achievement; import com.godsandtowers.campaigns.CampaignLevel; import com.godsandtowers.core.grid.Board; import com.godsandtowers.sprites.Creature; import com.godsandtowers.sprites.Player; import com.godsandtowers.sprites.Races; import com.godsandtowers.sprites.Tower; public class GameInfo implements Externalizable { private static final long AVERAGE_GAME_LENGTH = 10 * 60 * 1000; // in minutes public static final int DEFENSE = 0; public static final int BATTLE = 1; public static final int TUTORIAL = 2; public static final int SLOW = 15000; // ms public static final int NORMAL = 10000; // ms public static final int FAST = 5000; // ms public static final int BATTLE_WAVES = Integer.MAX_VALUE; public static final int NORMAL_WAVES = 100; private boolean noXP; private boolean won; private boolean disconnected; private int localPlayerID; private int gameType; private int timeUntilNextWave; private int timeBetweenWaves; private int currentWave; private int maxWaves; private int achievementModifier; private long length; private Board board; private CampaignLevel campaignLevel; private PlayerInfo[] playerInfos; private Player[] players; private ArrayList<Achievement> achievements; public GameInfo() { } public GameInfo(int localPlayerID, Player[] players, int timeUntilNextWave, int gameType, int maxWaves, Board board) { this(localPlayerID, players, timeUntilNextWave, gameType, maxWaves, null, board); } public GameInfo(int localPlayerID, Player[] players, int timeUntilNextWave, int gameType, int maxWaves, CampaignLevel campaignLevel, Board board) { this.board = board; this.players = players; this.localPlayerID = localPlayerID; this.campaignLevel = campaignLevel; this.gameType = gameType; this.timeUntilNextWave = timeUntilNextWave; this.timeBetweenWaves = timeUntilNextWave; this.currentWave = 1; this.maxWaves = maxWaves; this.won = false; this.disconnected = false; this.playerInfos = new PlayerInfo[players.length]; this.achievements = new ArrayList<Achievement>(); for (int i = 0; i < players.length; i++) { Player player = players[i]; playerInfos[i] = new PlayerInfo(player.getPlayerStats().getCurrentLevel(), player.getRace().getRaces(), player.getLife(), player.getGold()); } achievementModifier = 1; for (Achievement achievement : players[localPlayerID].getPlayerStats().getAchievements()) { if (achievement.isCompleted()) achievementModifier += achievement.getAchievementLevel(); } } public PlayerInfo[] getPlayerInfos() { return playerInfos; } public PlayerInfo getPlayerInfo(int player) { return playerInfos[player]; } public Player[] getPlayers() { return players; } public Player getPlayer(int player) { return players[player]; } public Player getLocalPlayer() { return players[localPlayerID]; } public int getWinnerID() { if (won) return localPlayerID; else return 1 - localPlayerID; } public void setWinner(int winnerID) { if (winnerID == localPlayerID) won = true; else won = false; } public Board getBoard() { return board; } public int getTimeBetweenWaves() { return timeBetweenWaves; } public int getTimeUntilNextWave() { return timeUntilNextWave; } public int getCurrentWave() { return currentWave; } public int getMaxWaves() { return maxWaves; } public int getGameType() { return gameType; } public int getLocalPlayerRaces() { return playerInfos[localPlayerID].getRaces(); } public long getLength() { return length; } public int getComputerLevel() { int level = 0; for (int i = 0; i < playerInfos.length; i++) { if (i != localPlayerID) level += playerInfos[i].getLevel(); } return level; } public long getPlayerLevel() { return playerInfos[localPlayerID].getLevel(); } public CampaignLevel getCampaignLevel() { return campaignLevel; } public ArrayList<Achievement> getAchievements() { return achievements; } public void setNoXP(boolean noXP) { this.noXP = noXP; } public long getXP() { long XP = getBaseXP(); XP *= getAchievementBonus(); XP *= getWinBonus(); XP *= getLengthBonus(); XP *= getLifeBonus(); XP *= getMultipleRaceFactor(); return noXP ? 0 : XP; } public int getLocalPlayerID() { return localPlayerID; } public long getBaseXP() { return Math.round(Math.log1p(playerInfos[localPlayerID].getScore())); } public int getAchievementBonus() { return achievementModifier; } public boolean won() { return won; } public boolean disconnected() { return disconnected; } public int getWinBonus() { return (won() ? 5 : 1); } public int getLengthBonus() { return (getLength() < AVERAGE_GAME_LENGTH && won() ? 2 : 1); } public int getLifeBonus() { return (compareStartEndLife(localPlayerID) ? 2 : 1); } public float getMultipleRaceFactor() { int numRaces = Races.asArray(playerInfos[localPlayerID].getRaces()).length; if (numRaces <= 1) return 1f; else return 1.5f / numRaces; } private boolean compareStartEndLife(int playerID) { PlayerInfo player = playerInfos[playerID]; return Float.floatToIntBits(player.getFirstLife()) == Float.floatToIntBits(player.getLastLife()); } public int getStarCount() { // In campaign, Lose 1 star for not having max health. Lose the other for over 5 minutes (battle only). Lose // the other for playing on normal speed, lose 2 for playing of slow speed int stars = 5; if (!compareStartEndLife(localPlayerID)) { stars--; } if (getGameType() == GameInfo.BATTLE && getLength() > AVERAGE_GAME_LENGTH) { stars--; } switch (getTimeUntilNextWave()) { case GameInfo.SLOW: stars--; case GameInfo.NORMAL: stars--; case GameInfo.FAST: default: } return stars; } public void removePlayers() { players = null; } public void addAchievement(Achievement achievement) { achievements.add(achievement); } public void setWon(boolean won) { this.won = won; } public void setDisconnected(boolean disconnected) { this.disconnected = disconnected; } public void setLength(long length) { this.length = length; } public void setCurrentWave(int currentWave) { this.currentWave = currentWave; } public void setTimeUntilNextWave(int timeUntilNextWave) { this.timeUntilNextWave = timeUntilNextWave; } public void creaturePurchased(int playerID, Creature creature) { PlayerInfo info = playerInfos[playerID]; info.addOffensivePower(creature.getPower(), currentWave); info.addScore(creature.getPower()); } public void towerPurchased(int playerID, Tower tower) { PlayerInfo info = playerInfos[playerID]; info.addDefensivePower(tower.getPower(), currentWave); } public void towerUpgraded(int playerID, Tower oldTower, Tower newTower) { PlayerInfo info = playerInfos[playerID]; info.addDefensivePower(newTower.getPower() - oldTower.getPower(), currentWave); } public void towerSold(int playerID, Tower tower) { PlayerInfo info = playerInfos[playerID]; info.subtractDefensivePower(tower.getPower(), currentWave); } public void creaturesKilled(int playerID, ArrayList<Creature> creatures) { PlayerInfo info = playerInfos[playerID]; for (Creature creature : creatures) { info.addScore(creature.getPower()); } } public void towersDestroyed(int playerID, ArrayList<Tower> towers) { PlayerInfo info = playerInfos[playerID]; for (Tower tower : towers) { info.addScore(tower.getPower()); } } public boolean update(int timePassed) { length += timePassed; for (int i = 0; i < players.length; i++) { Player player = players[i]; PlayerInfo info = playerInfos[i]; info.setIncome(player.getIncome(), currentWave); info.setLife(player.getLife(), currentWave); } timeUntilNextWave -= timePassed; if (timeUntilNextWave <= 0) { timeUntilNextWave = timeBetweenWaves; currentWave++; return true; } return false; } @Override public String toString() { return "GameInfo [campaignLevel=" + campaignLevel + ", gameType=" + gameType + ", remainingTimeUntilNextWave=" + timeUntilNextWave + ", timeUntilNextWave=" + timeBetweenWaves + ", currentWave=" + currentWave + ", maxWaves=" + maxWaves + ", length=" + length + ", won=" + won + ", playerInfo=" + Arrays.toString(playerInfos) + "]"; } @SuppressWarnings("unchecked") @Override public void readExternal(ObjectInput input) throws IOException, ClassNotFoundException { won = input.readBoolean(); disconnected = input.readBoolean(); gameType = input.readInt(); localPlayerID = input.readInt(); currentWave = input.readInt(); maxWaves = input.readInt(); timeUntilNextWave = input.readInt(); timeBetweenWaves = input.readInt(); achievementModifier = input.readInt(); length = input.readLong(); campaignLevel = (CampaignLevel) input.readObject(); players = (Player[]) input.readObject(); playerInfos = (PlayerInfo[]) input.readObject(); achievements = (ArrayList<Achievement>) input.readObject(); board = (Board) input.readObject(); } @Override public void writeExternal(ObjectOutput output) throws IOException { output.writeBoolean(won); output.writeBoolean(disconnected); output.writeInt(gameType); output.writeInt(localPlayerID); output.writeInt(currentWave); output.writeInt(maxWaves); output.writeInt(timeUntilNextWave); output.writeInt(timeBetweenWaves); output.writeInt(achievementModifier); output.writeLong(length); output.writeObject(campaignLevel); output.writeObject(players); output.writeObject(playerInfos); output.writeObject(achievements); output.writeObject(board); } }