/* * UFO Saved Game Editor * Copyright (C) 2010 Christopher Davoren * * 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 net.rubikscomplex.ufosge.data; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Formatter; import java.util.Iterator; import net.rubikscomplex.ufosge.UFOInfo; import net.rubikscomplex.ufosge.util.UFOInputStream; import net.rubikscomplex.ufosge.util.UFOOutputStream; /** * * @author Chris Davoren */ public class SavedGame { public int slot; public ArrayList<Base> bases; public ArrayList<Soldier> soldiers; public ArrayList<ProducibleItem> producibleItems; public ArrayList<Research> researchItems; public ArrayList<Facility> facilities; public ArrayList<UPItem> UPItems; public ArrayList<Craft> crafts; public ArrayList<Location> locations; public SaveInfo info; public FinancialInfo finances; public String sourceDirectory; public long lastModifiedTime; public static ArrayList<SaveInfo> loadSummaries(String baseDir) throws IOException { ArrayList<SaveInfo> sgSummaries = new ArrayList<SaveInfo>(); File baseDirFile = new File(baseDir); if (!baseDirFile.exists() || !baseDirFile.isDirectory()) { throw new IOException("Given base directory '" + baseDir + "' does not exist"); } for(int i = UFOInfo.MIN_SAVED_GAME; i <= UFOInfo.MAX_SAVED_GAME; i++) { File saveInfoFile = new File(baseDirFile, UFOInfo.SG_DIR_PREFIX + i + File.separator + UFOInfo.SAVEINFO_FILENAME); if (saveInfoFile.exists()) { SaveInfo info = new SaveInfo(); info.readFromFile(new UFOInputStream(new FileInputStream(saveInfoFile))); info.slot = i; sgSummaries.add(info); } } return sgSummaries; } public static SavedGame loadSavedGame(String baseDir, int slot) throws IOException { String sgDir = baseDir + File.separator + UFOInfo.SG_DIR_PREFIX + slot + File.separator; SavedGame game = new SavedGame(); game.slot = slot; UFOInputStream infoStream = new UFOInputStream(new FileInputStream(sgDir + UFOInfo.SAVEINFO_FILENAME)); game.info = new SaveInfo(); game.info.readFromFile(infoStream); infoStream.close(); UFOInputStream financialStream = new UFOInputStream(new FileInputStream(sgDir + UFOInfo.LIGLOB_FILENAME)); game.finances = new FinancialInfo(); game.finances.readFromFile(financialStream); financialStream.close(); UFOInputStream baseStream = new UFOInputStream(new FileInputStream(sgDir + UFOInfo.BASE_FILENAME)); game.bases = Base.readList(baseStream); baseStream.close(); UFOInputStream soldierStream = new UFOInputStream(new FileInputStream(sgDir + UFOInfo.SOLDIER_FILENAME)); game.soldiers = Soldier.readList(soldierStream); soldierStream.close(); UFOInputStream producibleItemStream = new UFOInputStream(new FileInputStream(sgDir + UFOInfo.PRODUCT_FILENAME)); game.producibleItems = ProducibleItem.readList(producibleItemStream); producibleItemStream.close(); UFOInputStream researchStream = new UFOInputStream(new FileInputStream(sgDir + UFOInfo.RESEARCH_FILENAME)); game.researchItems = Research.readList(researchStream); researchStream.close(); UFOInputStream facilityStream = new UFOInputStream(new FileInputStream(sgDir + UFOInfo.FACILITY_FILENAME)); game.facilities = Facility.readList(facilityStream); facilityStream.close(); UFOInputStream UPStream = new UFOInputStream(new FileInputStream(sgDir + UFOInfo.UP_FILENAME)); game.UPItems = UPItem.readList(UPStream); UPStream.close(); UFOInputStream craftStream = new UFOInputStream(new FileInputStream(sgDir + UFOInfo.CRAFT_FILENAME)); game.crafts = Craft.readList(craftStream); craftStream.close(); UFOInputStream locationStream = new UFOInputStream((new FileInputStream(sgDir + UFOInfo.LOCATION_FILENAME))); game.locations = Location.readList(locationStream); locationStream.close(); game.sourceDirectory = sgDir; game.lastModifiedTime = new File(sgDir + UFOInfo.SAVEINFO_FILENAME).lastModified(); return game; } public void saveSavedGame(String baseDir) throws IOException { String sgDir = baseDir + File.separator + UFOInfo.SG_DIR_PREFIX + slot + File.separator; // System.out.println(sgDir); UFOOutputStream infoStream = new UFOOutputStream(new FileOutputStream(sgDir + UFOInfo.SAVEINFO_FILENAME)); info.writeToFile(infoStream); infoStream.close(); UFOOutputStream financialStream = new UFOOutputStream(new FileOutputStream(sgDir + UFOInfo.LIGLOB_FILENAME)); finances.writeToFile(financialStream); financialStream.close(); UFOOutputStream soldierStream = new UFOOutputStream(new FileOutputStream(sgDir + UFOInfo.SOLDIER_FILENAME)); Soldier.writeList(soldierStream, soldiers); soldierStream.close(); UFOOutputStream baseStream = new UFOOutputStream(new FileOutputStream(sgDir + UFOInfo.BASE_FILENAME)); Base.writeList(baseStream, bases); baseStream.close(); UFOOutputStream producibleItemStream = new UFOOutputStream(new FileOutputStream(sgDir + UFOInfo.PRODUCT_FILENAME)); ProducibleItem.writeList(producibleItemStream, producibleItems); producibleItemStream.close(); UFOOutputStream researchStream = new UFOOutputStream(new FileOutputStream(sgDir + UFOInfo.RESEARCH_FILENAME)); Research.writeList(researchStream, researchItems); researchStream.close(); UFOOutputStream facilityStream = new UFOOutputStream(new FileOutputStream(sgDir + UFOInfo.FACILITY_FILENAME)); Facility.writeList(facilityStream, facilities); facilityStream.close(); UFOOutputStream UPStream = new UFOOutputStream(new FileOutputStream(sgDir + UFOInfo.UP_FILENAME)); UPItem.writeList(UPStream, UPItems); UPStream.close(); UFOOutputStream craftStream = new UFOOutputStream(new FileOutputStream(sgDir + UFOInfo.CRAFT_FILENAME)); Craft.writeList(craftStream, crafts); craftStream.close(); UFOOutputStream locationsStream = new UFOOutputStream(new FileOutputStream(sgDir + UFOInfo.LOCATION_FILENAME)); Location.writeList(locationsStream, locations); locationsStream.close(); lastModifiedTime = new File(sgDir + UFOInfo.SAVEINFO_FILENAME).lastModified(); } public void printToConsole() { System.out.println("Saved game information:"); System.out.println(" Name: " + info.name); System.out.println(" Time: " + info.formatTime()); System.out.println(soldiers.size() + " soldier(s) read."); System.out.println("Soldier list:"); int soldiersAlive = 0, soldiersFound = 0; Iterator<Soldier> soldierIterator = soldiers.iterator(); while(soldierIterator.hasNext()) { Soldier s = soldierIterator.next(); if (s.isUsed()) { System.out.println(" (" + Soldier.rankToAbbrString(s.rank) + ") " + s.name); soldiersAlive += s.rank != Soldier.RANK_DEAD ? 1 : 0; soldiersFound++; } } System.out.println("Total of " + soldiersFound + " soldier(s) found (" + (soldiersFound == soldiersAlive ? "all" : soldiersAlive) + " alive)."); System.out.println(bases.size() + " base(s) read."); System.out.println("Base list:"); int basesFound = 0; Iterator<Base> baseIterator = bases.iterator(); while (baseIterator.hasNext()) { Base b = baseIterator.next(); if (b.isActive) { System.out.println(" [" + b.index + "] " + b.name + " (engineers: " + b.engineers + ", scientists: " + b.scientists + ")"); System.out.println(" sr: " + b.shortRange); System.out.println(" lr: " + b.longRange); System.out.println(" hr: " + b.hyperwaveRange); for (int i = 0; i < Base.INVENTORY_SIZE; i++) { System.out.println (" " + new Formatter().format("%1$02d", i) + " " + Base.INV_NAMES[i] + ": " + b.inventory[i]); } basesFound++; } } System.out.println("Total of " + basesFound + " base(s) active."); System.out.println(producibleItems.size() + " producible item(s) read."); System.out.println("Producible items:"); int buildableItems = 0; Iterator<ProducibleItem> itemsIterator = producibleItems.iterator(); while (itemsIterator.hasNext()) { ProducibleItem i = itemsIterator.next(); if (i.buildable) { System.out.println(" " + ProducibleItem.ITEM_NAMES[i.index]); buildableItems++; } } System.out.println("Total of " + buildableItems + " item(s) producible."); System.out.println(researchItems.size() + " research item(s) read."); System.out.println("Research items: "); int completedItems = 0; int numPrerequisitesMet = 0; DecimalFormat df = new DecimalFormat(); df.setMinimumIntegerDigits(2); df.setMaximumIntegerDigits(2); Iterator<Research> ri = researchItems.iterator(); while(ri.hasNext()) { Research r = ri.next(); Formatter f = new Formatter(); System.out.println(" " + new Formatter().format("%1$02X", r.index) + " " + new Formatter().format("%1$-27s", Research.PROJECT_NAMES[r.index]) + ": " + f.format("%1$02X %2$02X %3$02X %4$02X", r.topicInfo[0], r.topicInfo[1], r.topicInfo[2], r.unknown1) + " " + r.prerequisitesRequired); completedItems += r.completed ? 1 : 0; numPrerequisitesMet += r.prerequisitesMet ? 1 : 0; } System.out.println("Total of " + completedItems + " completed item(s) and " + numPrerequisitesMet + " item(s) with met prerequisites."); System.out.println(facilities.size() + " facilities read."); System.out.println(" # Name B R Cost"); System.out.println(" ------------------------------------------------"); Iterator<Facility> bi = facilities.iterator(); while(bi.hasNext()) { Facility bf = bi.next(); System.out.println(new Formatter().format(" %1$02X %2$-20s : %3$-5S %4$-5S $%5$8d", bf.index, Facility.FACILITY_NAMES[bf.index], bf.buildable, bf.requiresResearch, bf.cost)); } System.out.println(crafts.size() + " craft read."); int craftUsed = 0; Iterator<Craft> ci = crafts.iterator(); while(ci.hasNext()) { Craft c = ci.next(); if (c.type != Craft.TYPE_UNUSED) { craftUsed++; System.out.println(new Formatter().format(" %1$02X %2$02X %3$02X %4$02X %5$04X %6$04X", c.index, c.type, c.leftType, c.rightType, c.baseIndex, c.status)); } } System.out.println("Total of " + craftUsed + " craft used."); System.out.println(locations.size() + " location(s) read."); int locationsUsed = 0; Iterator<Location> li = locations.iterator(); while(li.hasNext()) { Location l = li.next(); if (l.type != Location.TYPE_UNUSED) { locationsUsed++; System.out.println(new Formatter().format(" %1$02X %2$02X %3$04X", l.type, l.reference, l.countSuffix)); } } System.out.println("Total of " + locationsUsed + " location(s) used."); System.out.println(UPItems.size() + " UFOpaedia item(s) read."); Iterator<UPItem> upi = UPItems.iterator(); while(upi.hasNext()) { UPItem up = upi.next(); System.out.println (new Formatter().format(" %1$02X %2$02X %3$02X", up.category, up.nameIndex, up.researchFlag)); } } public int usedSoldierSlots() { int usedSlots = 0; for(int i = 0; i < soldiers.size(); i++) { if (soldiers.get(i).isUsed()) { usedSlots++; } } return usedSlots; } public SavedGameStatistics getStatistics() { SavedGameStatistics stats = new SavedGameStatistics(); stats.numBases = 0; stats.numActiveBases = 0; for (int i = 0; i < bases.size(); i++) { if (bases.get(i).isActive) { stats.numActiveBases++; stats.numBases++; } else if (bases.get(i).name.length() > 0) { stats.numBases++; } } stats.numSoldiers = 0; stats.numAliveSoldiers = 0; for(int i = 0; i < soldiers.size(); i++) { if (soldiers.get(i).rank != Soldier.RANK_DEAD) { stats.numSoldiers++; stats.numAliveSoldiers++; } else if(soldiers.get(i).isUsed()) { stats.numSoldiers++; } } for(int i = 0; i < producibleItems.size(); i++) { if (producibleItems.get(i).buildable) { stats.numProducibleItems++; } } return stats; } public ArrayList<Base> getActiveBases() { ArrayList<Base> activeBases = new ArrayList<Base>(); Iterator<Base> bi = bases.iterator(); while (bi.hasNext()) { Base b = bi.next(); if (b.isActive) { activeBases.add(b); } } return activeBases; } public boolean hasBeenModified() { return new File(sourceDirectory + UFOInfo.SAVEINFO_FILENAME).lastModified() != lastModifiedTime; } }