/* * Pixel Dungeon * Copyright (C) 2012-2015 Oleg Dolya * * Shattered Pixel Dungeon * Copyright (C) 2014-2015 Evan Debenham * * 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 */ package com.shatteredpixel.shatteredpixeldungeon; import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.ToxicGas; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Bleeding; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Burning; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Hunger; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Ooze; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Poison; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroClass; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.DM300; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Goo; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.King; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Tengu; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Yog; import com.shatteredpixel.shatteredpixeldungeon.items.Amulet; import com.shatteredpixel.shatteredpixeldungeon.levels.features.Chasm; import com.shatteredpixel.shatteredpixeldungeon.messages.Languages; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.watabou.noosa.Game; import com.watabou.utils.Bundlable; import com.watabou.utils.Bundle; import com.watabou.utils.SystemTime; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Locale; public enum Rankings { INSTANCE; public static final int TABLE_SIZE = 11; public static final String RANKINGS_FILE = "rankings.dat"; public static final String DETAILS_FILE = "game_%d.dat"; public ArrayList records; public int lastRecord; public int totalNumber; public int wonNumber; public void submit( boolean win, Class cause ) { load(); Record rec = new Record(); rec.cause = cause; rec.win = win; rec.heroClass = Dungeon.hero.heroClass; rec.armorTier = Dungeon.hero.tier(); rec.herolevel = Dungeon.hero.lvl; rec.depth = Dungeon.depth; rec.score = score( win ); String gameFile = Messages.format( DETAILS_FILE, SystemTime.now ); try { Dungeon.saveGame( gameFile ); rec.gameFile = gameFile; } catch (IOException e) { rec.gameFile = ""; } records.add( rec ); Collections.sort( records, scoreComparator ); lastRecord = records.indexOf( rec ); int size = records.size(); while (size > TABLE_SIZE) { Record removedGame; if (lastRecord == size - 1) { removedGame = records.remove( size - 2 ); lastRecord--; } else { removedGame = records.remove( size - 1 ); } if (removedGame.gameFile.length() > 0) { Game.instance.deleteFile( removedGame.gameFile ); } size = records.size(); } totalNumber++; if (win) { wonNumber++; } Badges.validateGamesPlayed(); save(); } private int score( boolean win ) { return (Statistics.goldCollected + Dungeon.hero.lvl * (win ? 26 : Dungeon.depth ) * 100) * (win ? 2 : 1); } private static final String RECORDS = "records"; private static final String LATEST = "latest"; private static final String TOTAL = "total"; private static final String WON = "won"; public void save() { Bundle bundle = new Bundle(); bundle.put( RECORDS, records ); bundle.put( LATEST, lastRecord ); bundle.put( TOTAL, totalNumber ); bundle.put( WON, wonNumber ); try { OutputStream output = Game.instance.openFileOutput( RANKINGS_FILE, Game.MODE_PRIVATE ); Bundle.write( bundle, output ); output.close(); } catch (IOException e) { } } public void load() { if (records != null) { return; } records = new ArrayList(); try { InputStream input = Game.instance.openFileInput( RANKINGS_FILE ); Bundle bundle = Bundle.read( input ); input.close(); for (Bundlable record : bundle.getCollection( RECORDS )) { records.add( (Record)record ); } lastRecord = bundle.getInt( LATEST ); totalNumber = bundle.getInt( TOTAL ); if (totalNumber == 0) { totalNumber = records.size(); } wonNumber = bundle.getInt( WON ); if (wonNumber == 0) { for (Record rec : records) { if (rec.win) { wonNumber++; } } } } catch (IOException e) { } } public static class Record implements Bundlable { //pre 0.3.4 public String info; private static final String REASON = "reason"; private static final String CAUSE = "cause"; private static final String WIN = "win"; private static final String SCORE = "score"; private static final String TIER = "tier"; private static final String LEVEL = "level"; private static final String DEPTH = "depth"; private static final String GAME = "gameFile"; public Class cause; public boolean win; public HeroClass heroClass; public int armorTier; public int herolevel; public int depth; public int score; public String gameFile; public String desc(){ if (cause == null) { if (info != null){ //support for pre-0.3.4 saves if (Messages.lang() == Languages.ENGLISH) { return info; } else { return Messages.get(this, "something"); } } else { return Messages.get(this, "something"); } } else { String result = Messages.get(cause, "rankings_desc", (Messages.get(cause, "name"))); if (result.contains("!!!NO TEXT FOUND!!!")){ return Messages.get(this, "something"); } else { return result; } } } @Override public void restoreFromBundle( Bundle bundle ) { //conversion logic for pre-0.3.4 saves if (bundle.contains( REASON )){ String info = bundle.getString( REASON ).toLowerCase(Locale.ENGLISH); if (info.equals("obtained the amulet of yendor")) cause = Amulet.class; else if (info.contains("goo")) cause = Goo.class; else if (info.contains("tengu")) cause = Tengu.class; else if (info.contains("dm-300")) cause = DM300.class; else if (info.contains("king")) cause = King.class; else if (info.contains("yog")) cause = Yog.class; else if (info.contains("fist")) cause = Yog.class; else if (info.contains("larva")) cause = Yog.class; else if (info.equals("burned to ash")) cause = Burning.class; else if (info.equals("starved to death")) cause = Hunger.class; else if (info.equals("succumbed to poison")) cause = Poison.class; else if (info.equals("suffocated")) cause = ToxicGas.class; else if (info.equals("bled to death")) cause = Bleeding.class; else if (info.equals("melted away")) cause = Ooze.class; else if (info.equals("died on impact")) cause = Chasm.class; //can't get the all, just keep what remains as-is else this.info = info; } else { cause = bundle.getClass( CAUSE ); } win = bundle.getBoolean( WIN ); score = bundle.getInt( SCORE ); heroClass = HeroClass.restoreInBundle( bundle ); armorTier = bundle.getInt( TIER ); gameFile = bundle.getString( GAME ); depth = bundle.getInt( DEPTH ); herolevel = bundle.getInt( LEVEL ); } @Override public void storeInBundle( Bundle bundle ) { if (info != null) bundle.put( REASON, info ); else bundle.put( CAUSE, cause ); bundle.put( WIN, win ); bundle.put( SCORE, score ); heroClass.storeInBundle( bundle ); bundle.put( TIER, armorTier ); bundle.put( LEVEL, herolevel ); bundle.put( DEPTH, depth ); bundle.put( GAME, gameFile ); } } private static final Comparator scoreComparator = new Comparator() { @Override public int compare( Record lhs, Record rhs ) { return (int)Math.signum( rhs.score - lhs.score ); } }; }