/*
* 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;
}
}