diff --git a/core/src/main/assets/interfaces/icons.png b/core/src/main/assets/interfaces/icons.png index b1d2ffabb..6835e9314 100644 Binary files a/core/src/main/assets/interfaces/icons.png and b/core/src/main/assets/interfaces/icons.png differ diff --git a/core/src/main/assets/messages/scenes/scenes.properties b/core/src/main/assets/messages/scenes/scenes.properties index 736c7fa0f..51b32f04b 100644 --- a/core/src/main/assets/messages/scenes/scenes.properties +++ b/core/src/main/assets/messages/scenes/scenes.properties @@ -47,6 +47,10 @@ scenes.gamescene.trample=Trample scenes.gamescene.examine=Examine scenes.heroselectscene.title=Choose Your Hero +scenes.heroselectscene.custom_seed_title=Enter a Custom Seed +scenes.heroselectscene.custom_seed_desc=The same seed and game version always generate the same dungeon! Seeds are nine uppercase letters (e.g. ABC-DEF-GHI), but you can enter anything you want and the game will convert it. _Games with a custom seed cannot earn badges or appear in rankings._ +scenes.heroselectscene.custom_seed_set=Set +scenes.heroselectscene.custom_seed_clear=Clear scenes.interlevelscene$mode.descend=Descending... scenes.interlevelscene$mode.ascend=Ascending... diff --git a/core/src/main/assets/messages/windows/windows.properties b/core/src/main/assets/messages/windows/windows.properties index c4dcc0458..3bde042c9 100644 --- a/core/src/main/assets/messages/windows/windows.properties +++ b/core/src/main/assets/messages/windows/windows.properties @@ -46,6 +46,8 @@ windows.wndgameinprogress.str=Strength windows.wndgameinprogress.health=Health windows.wndgameinprogress.gold=Gold Collected windows.wndgameinprogress.depth=Maximum Depth +windows.wndgameinprogress.dungeon_seed=Dungeon Seed +windows.wndgameinprogress.custom_seed=_Custom Seed_ windows.wndgameinprogress.continue=Continue windows.wndgameinprogress.erase=Erase windows.wndgameinprogress.erase_warn_title=Are you sure you want to delete this save? @@ -62,6 +64,8 @@ windows.wndhero$statstab.str=Strength windows.wndhero$statstab.health=Health windows.wndhero$statstab.gold=Gold Collected windows.wndhero$statstab.depth=Maximum Depth +windows.wndhero$statstab.dungeon_seed=Dungeon Seed +windows.wndhero$statstab.custom_seed=_Custom Seed_ windows.wndheroinfo.talents=talents windows.wndheroinfo.talents_msg=The hero gains one talent point each time they level up. Higher tier talents appear after defeating the second boss. diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Badges.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Badges.java index e1d2a30b8..b7d7a91be 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Badges.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Badges.java @@ -283,7 +283,7 @@ public class Badges { } } - public static int unlocked(boolean global){ + public static int totalUnlocked(boolean global){ if (global) return Badges.global.size(); else return Badges.local.size(); } @@ -533,7 +533,7 @@ public class Badges { for (Catalog cat : Catalog.values()){ if (cat.allSeen()){ Badge b = Catalog.catalogBadges.get(cat); - if (!global.contains(b)){ + if (!isUnlocked(b)){ displayBadge(b); } } @@ -654,7 +654,7 @@ public class Badges { break; } local.add( badge ); - addGlobal(badge); + unlock(badge); if (isUnlocked( Badge.BOSS_SLAIN_1_WARRIOR ) && isUnlocked( Badge.BOSS_SLAIN_1_MAGE ) && @@ -697,7 +697,7 @@ public class Badges { return; } local.add( badge ); - addGlobal(badge); + unlock(badge); if (isUnlocked( Badge.BOSS_SLAIN_3_GLADIATOR ) && isUnlocked( Badge.BOSS_SLAIN_3_BERSERKER ) && @@ -735,11 +735,11 @@ public class Badges { break; } - addGlobal(badge); + unlock(badge); } public static void validateRatmogrify(){ - addGlobal(Badge.FOUND_RATMOGRIFY); + unlock(Badge.FOUND_RATMOGRIFY); } public static void validateMageUnlock(){ @@ -788,7 +788,7 @@ public class Badges { break; } local.add( badge ); - addGlobal(badge); + unlock(badge); if (isUnlocked( Badge.VICTORY_WARRIOR ) && isUnlocked( Badge.VICTORY_MAGE ) && @@ -855,11 +855,11 @@ public class Badges { badge = Badge.CHAMPION_1; } if (challenges >= 3){ - addGlobal(badge); + unlock(badge); badge = Badge.CHAMPION_2; } if (challenges >= 6){ - addGlobal(badge); + unlock(badge); badge = Badge.CHAMPION_3; } local.add(badge); @@ -868,11 +868,11 @@ public class Badges { private static void displayBadge( Badge badge ) { - if (badge == null) { + if (badge == null || Dungeon.usingCustomSeed) { return; } - if (global.contains( badge )) { + if (isUnlocked( badge )) { if (!badge.meta) { GLog.h( Messages.get(Badges.class, "endorsed", badge.title()) ); @@ -881,8 +881,7 @@ public class Badges { } else { - global.add( badge ); - saveNeeded = true; + unlock(badge); GLog.h( Messages.get(Badges.class, "new", badge.title() + " (" + badge.desc() + ")") ); GLog.newLine(); @@ -905,8 +904,8 @@ public class Badges { saveNeeded = true; } - public static void addGlobal( Badge badge ){ - if (!global.contains(badge)){ + public static void unlock( Badge badge ){ + if (!isUnlocked(badge) && !Dungeon.usingCustomSeed){ global.add( badge ); saveNeeded = true; } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Bones.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Bones.java index ece3972ed..1ce2f68c6 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Bones.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Bones.java @@ -50,8 +50,8 @@ public class Bones { depth = Dungeon.depth; - //heroes which have won the game, who die far above their farthest depth, or who are challenged drop no bones. - if (Statistics.amuletObtained || (Statistics.deepestFloor - 5) >= depth || Dungeon.challenges > 0) { + //heroes drop no bones if they have the amulet, die far above their farthest depth, are challenged, or are playing with a custom seed. + if (Statistics.amuletObtained || (Statistics.deepestFloor - 5) >= depth || Dungeon.challenges > 0 || Dungeon.usingCustomSeed) { depth = -1; return; } @@ -141,8 +141,8 @@ public class Bones { } } else { - //heroes who are challenged cannot find bones - if (depth == Dungeon.depth && Dungeon.challenges == 0) { + //heroes who are challenged or on a seeded run cannot find bones + if (depth == Dungeon.depth && Dungeon.challenges == 0 && !Dungeon.usingCustomSeed) { Bundle emptyBones = new Bundle(); emptyBones.put(LEVEL, 0); try { diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java index 97c8476d9..5f8ba0e03 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java @@ -172,6 +172,7 @@ public class Dungeon { public static int version; public static long seed; + public static boolean usingCustomSeed; public static void init() { @@ -179,7 +180,13 @@ public class Dungeon { challenges = SPDSettings.challenges(); mobsToChampion = -1; - seed = DungeonSeed.randomSeed(); + if (SPDSettings.customSeed() != -1){ + seed = SPDSettings.customSeed(); + usingCustomSeed = true; + } else { + seed = DungeonSeed.randomSeed(); + usingCustomSeed = false; + } Actor.clear(); Actor.resetNextID(); @@ -441,6 +448,7 @@ public class Dungeon { private static final String VERSION = "version"; private static final String SEED = "seed"; + private static final String CUSTOM_SEED = "custom_seed"; private static final String CHALLENGES = "challenges"; private static final String MOBS_TO_CHAMPION = "mobs_to_champion"; private static final String HERO = "hero"; @@ -462,6 +470,7 @@ public class Dungeon { version = Game.versionCode; bundle.put( VERSION, version ); bundle.put( SEED, seed ); + bundle.put( CUSTOM_SEED, usingCustomSeed ); bundle.put( CHALLENGES, challenges ); bundle.put( MOBS_TO_CHAMPION, mobsToChampion ); bundle.put( HERO, hero ); @@ -537,7 +546,7 @@ public class Dungeon { saveGame( GamesInProgress.curSlot ); saveLevel( GamesInProgress.curSlot ); - GamesInProgress.set( GamesInProgress.curSlot, depth, challenges, hero ); + GamesInProgress.set( GamesInProgress.curSlot, depth, challenges, seed, usingCustomSeed, hero ); } } @@ -553,6 +562,7 @@ public class Dungeon { version = bundle.getInt( VERSION ); seed = bundle.contains( SEED ) ? bundle.getLong( SEED ) : DungeonSeed.randomSeed(); + usingCustomSeed = bundle.getBoolean( CUSTOM_SEED ); Actor.clear(); Actor.restoreNextID( bundle ); @@ -683,6 +693,9 @@ public class Dungeon { info.depth = bundle.getInt( DEPTH ); info.version = bundle.getInt( VERSION ); info.challenges = bundle.getInt( CHALLENGES ); + info.seed = bundle.getLong( SEED ); + info.customSeed = bundle.getBoolean( CUSTOM_SEED ); + Hero.preview( info, bundle.getBundle( HERO ) ); Statistics.preview( info, bundle ); } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/GamesInProgress.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/GamesInProgress.java index 8cc3b6718..99302fb26 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/GamesInProgress.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/GamesInProgress.java @@ -121,13 +121,16 @@ public class GamesInProgress { } } - public static void set(int slot, int depth, int challenges, + public static void set(int slot, int depth, int challenges, long seed, boolean customSeed, Hero hero) { Info info = new Info(); info.slot = slot; info.depth = depth; info.challenges = challenges; + + info.seed = seed; + info.customSeed = customSeed; info.level = hero.lvl; info.str = hero.STR; @@ -160,6 +163,9 @@ public class GamesInProgress { public int depth; public int version; public int challenges; + + public long seed; + public boolean customSeed; public int level; public int str; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Rankings.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Rankings.java index 5d18e3732..cf6050ca7 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Rankings.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Rankings.java @@ -61,6 +61,9 @@ public enum Rankings { public void submit( boolean win, Class cause ) { + //games with custom seeds do not appear in rankings + if (Dungeon.usingCustomSeed) return; + load(); Record rec = new Record(); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/SPDSettings.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/SPDSettings.java index b44693255..bba62b03e 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/SPDSettings.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/SPDSettings.java @@ -24,6 +24,7 @@ package com.shatteredpixel.shatteredpixeldungeon; import com.shatteredpixel.shatteredpixeldungeon.messages.Languages; import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; import com.shatteredpixel.shatteredpixeldungeon.scenes.PixelScene; +import com.shatteredpixel.shatteredpixeldungeon.utils.DungeonSeed; import com.watabou.noosa.Game; import com.watabou.noosa.audio.Music; import com.watabou.noosa.audio.Sample; @@ -179,6 +180,7 @@ public class SPDSettings extends GameSettings { public static final String KEY_LAST_CLASS = "last_class"; public static final String KEY_CHALLENGES = "challenges"; + public static final String KEY_CUSTOM_SEED = "custom_seed"; public static final String KEY_INTRO = "intro"; public static final String KEY_SUPPORT_NAGGED= "support_nagged"; @@ -207,6 +209,14 @@ public class SPDSettings extends GameSettings { return getInt( KEY_CHALLENGES, 0, 0, Challenges.MAX_VALUE ); } + public static void customSeed( long value ){ + put( KEY_CUSTOM_SEED, value ); + } + + public static long customSeed() { + return getLong( KEY_CUSTOM_SEED, -1, -1, DungeonSeed.TOTAL_SEEDS-1); + } + public static void supportNagged( boolean value ) { put( KEY_SUPPORT_NAGGED, value ); } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/HeroSelectScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/HeroSelectScene.java index 36c54ea57..5b60b9228 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/HeroSelectScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/HeroSelectScene.java @@ -21,8 +21,6 @@ package com.shatteredpixel.shatteredpixeldungeon.scenes; -import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.graphics.GL20; import com.shatteredpixel.shatteredpixeldungeon.Badges; import com.shatteredpixel.shatteredpixeldungeon.Chrome; import com.shatteredpixel.shatteredpixeldungeon.Dungeon; @@ -40,6 +38,8 @@ import com.shatteredpixel.shatteredpixeldungeon.ui.Icons; import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock; import com.shatteredpixel.shatteredpixeldungeon.ui.StyledButton; import com.shatteredpixel.shatteredpixeldungeon.ui.Window; +import com.shatteredpixel.shatteredpixeldungeon.ui.WndTextInput; +import com.shatteredpixel.shatteredpixeldungeon.utils.DungeonSeed; import com.shatteredpixel.shatteredpixeldungeon.windows.WndChallenges; import com.shatteredpixel.shatteredpixeldungeon.windows.WndHeroInfo; import com.shatteredpixel.shatteredpixeldungeon.windows.WndKeyBindings; @@ -64,6 +64,7 @@ public class HeroSelectScene extends PixelScene { private ArrayList heroBtns = new ArrayList<>(); private StyledButton startBtn; private IconButton infoButton; + private IconButton seedButton; private IconButton challengeButton; private IconButton btnExit; @@ -146,7 +147,7 @@ public class HeroSelectScene extends PixelScene { } }; infoButton.visible = false; - infoButton.setSize(21, 21); + infoButton.setSize(20, 21); add(infoButton); HeroClass[] classes = HeroClass.values(); @@ -192,14 +193,67 @@ public class HeroSelectScene extends PixelScene { return Messages.titleCase(Messages.get(WndChallenges.class, "title")); } }; - challengeButton.setRect(heroBtnleft + 16, Camera.main.height-HeroBtn.HEIGHT-16, 21, 21); + challengeButton.setRect(heroBtnleft + 16, Camera.main.height-HeroBtn.HEIGHT-16, 20, 21); challengeButton.visible = false; + seedButton = new IconButton( Icons.get(Icons.SEED)){ + @Override + protected void onClick() { + String existingSeedtext = SPDSettings.customSeed() == -1 ? "" : DungeonSeed.convertToCode(SPDSettings.customSeed()); + ShatteredPixelDungeon.scene().addToFront( new WndTextInput(Messages.get(HeroSelectScene.class, "custom_seed_title"), + Messages.get(HeroSelectScene.class, "custom_seed_desc"), + existingSeedtext, + 30, + false, + Messages.get(HeroSelectScene.class, "custom_seed_set"), + Messages.get(HeroSelectScene.class, "custom_seed_clear")){ + @Override + public void onSelect(boolean positive, String text) { + long seed = DungeonSeed.convertFromText(text); + if (positive && seed != -1){ + SPDSettings.customSeed(seed); + icon.hardlight(1f, 1.5f, 0.67f); + } else { + SPDSettings.customSeed(-1); + icon.resetColor(); + } + } + }); + } + + @Override + protected void onPointerUp() { + if (SPDSettings.customSeed() != -1){ + icon.hardlight(1f, 1.5f, 0.67f); + } else { + icon.resetColor(); + } + } + + @Override + public void update() { + if( !visible && GamesInProgress.selectedClass != null){ + visible = true; + } + super.update(); + } + + @Override + protected String hoverText() { + return Messages.get(HeroSelectScene.class, "custom_seed_title"); + } + }; + if (SPDSettings.customSeed() != -1) seedButton.icon().hardlight(1f, 1.5f, 0.67f); + seedButton.setRect(challengeButton.left()-16, challengeButton.top(), 16, 21); + seedButton.visible = false; + if (DeviceCompat.isDebug() || Badges.isUnlocked(Badges.Badge.VICTORY)){ + add(seedButton); add(challengeButton); } else { Dungeon.challenges = 0; SPDSettings.challenges(0); + SPDSettings.customSeed(-1); } btnExit = new ExitButton(); @@ -251,6 +305,9 @@ public class HeroSelectScene extends PixelScene { challengeButton.visible = true; challengeButton.setPos(startBtn.left()-challengeButton.width(), startBtn.top()); + + seedButton.visible = true; + seedButton.setPos(challengeButton.left()-seedButton.width(), challengeButton.top()); } private float uiAlpha; @@ -274,6 +331,7 @@ public class HeroSelectScene extends PixelScene { startBtn.alpha(alpha); btnExit.icon().alpha(alpha); challengeButton.icon().alpha(alpha); + seedButton.icon().alpha(alpha); infoButton.icon().alpha(alpha); } } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/StartScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/StartScene.java index 32e48b577..385df840b 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/StartScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/StartScene.java @@ -202,6 +202,10 @@ public class StartScene extends PixelScene { depth.resetColor(); level.resetColor(); } + + if (info.customSeed){ + steps.hardlight(1f, 1.5f, 0.67f); + } } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/Icons.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/Icons.java index b07f0ea5f..84ca5e424 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/Icons.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/Icons.java @@ -22,6 +22,7 @@ package com.shatteredpixel.shatteredpixeldungeon.ui; import com.shatteredpixel.shatteredpixeldungeon.Assets; +import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroClass; import com.shatteredpixel.shatteredpixeldungeon.levels.Level; import com.shatteredpixel.shatteredpixeldungeon.scenes.PixelScene; @@ -60,6 +61,7 @@ public enum Icons { CHALLENGE_ON, RENAME_OFF, RENAME_ON, + SEED, LEFTARROW, RIGHTARROW, @@ -92,7 +94,7 @@ public enum Icons { SLEEP, ALERT, LOST, - DEPTH, + DEPTH, //depth icons have two variants, for regular and seeded runs DEPTH_CHASM, DEPTH_WATER, DEPTH_GRASS, @@ -203,11 +205,14 @@ public enum Icons { case RENAME_ON: icon.frame( icon.texture.uvRectBySize( 176, 32, 15, 14 ) ); break; + case SEED: + icon.frame( icon.texture.uvRectBySize( 192, 32, 10, 10 ) ); + break; case LEFTARROW: - icon.frame( icon.texture.uvRectBySize( 192, 32, 14, 8 ) ); + icon.frame( icon.texture.uvRectBySize( 208, 32, 14, 8 ) ); break; case RIGHTARROW: - icon.frame( icon.texture.uvRectBySize( 208, 32, 14, 8 ) ); + icon.frame( icon.texture.uvRectBySize( 224, 32, 14, 8 ) ); break; case UNCHECKED: @@ -290,31 +295,31 @@ public enum Icons { icon.frame( icon.texture.uvRectBySize( 40, 72, 8, 8 ) ); break; case DEPTH: - icon.frame( icon.texture.uvRectBySize( 48, 64, 6, 7 ) ); + icon.frame( icon.texture.uvRectBySize( 48, 64 + (Dungeon.usingCustomSeed ? 8 : 0), 6, 7 ) ); break; case DEPTH_CHASM: - icon.frame( icon.texture.uvRectBySize( 56, 64, 7, 7 ) ); + icon.frame( icon.texture.uvRectBySize( 56, 64 + (Dungeon.usingCustomSeed ? 8 : 0), 7, 7 ) ); break; case DEPTH_WATER: - icon.frame( icon.texture.uvRectBySize( 64, 64, 7, 7 ) ); + icon.frame( icon.texture.uvRectBySize( 64, 64 + (Dungeon.usingCustomSeed ? 8 : 0), 7, 7 ) ); break; case DEPTH_GRASS: - icon.frame( icon.texture.uvRectBySize( 72, 64, 7, 7 ) ); + icon.frame( icon.texture.uvRectBySize( 72, 64 + (Dungeon.usingCustomSeed ? 8 : 0), 7, 7 ) ); break; case DEPTH_DARK: - icon.frame( icon.texture.uvRectBySize( 80, 64, 7, 7 ) ); + icon.frame( icon.texture.uvRectBySize( 80, 64 + (Dungeon.usingCustomSeed ? 8 : 0), 7, 7 ) ); break; case DEPTH_LARGE: - icon.frame( icon.texture.uvRectBySize( 88, 64, 7, 7 ) ); + icon.frame( icon.texture.uvRectBySize( 88, 64 + (Dungeon.usingCustomSeed ? 8 : 0), 7, 7 ) ); break; case DEPTH_TRAPS: - icon.frame( icon.texture.uvRectBySize( 96, 64, 7, 7 ) ); + icon.frame( icon.texture.uvRectBySize( 96, 64 + (Dungeon.usingCustomSeed ? 8 : 0), 7, 7 ) ); break; case DEPTH_SECRETS: - icon.frame( icon.texture.uvRectBySize( 104, 64, 7, 7 ) ); + icon.frame( icon.texture.uvRectBySize( 104, 64 + (Dungeon.usingCustomSeed ? 8 : 0), 7, 7 ) ); break; case CHAL_COUNT: - icon.frame( icon.texture.uvRectBySize( 48, 72, 7, 7 ) ); + icon.frame( icon.texture.uvRectBySize( 112, 64, 7, 7 ) ); break; case LIBGDX: diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/WndTextInput.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/WndTextInput.java index 26ab4b717..525ef1817 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/WndTextInput.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/WndTextInput.java @@ -21,7 +21,6 @@ package com.shatteredpixel.shatteredpixeldungeon.ui; -import com.badlogic.gdx.scenes.scene2d.ui.TextButton; import com.shatteredpixel.shatteredpixeldungeon.Chrome; import com.shatteredpixel.shatteredpixeldungeon.scenes.PixelScene; import com.watabou.noosa.TextInput; @@ -29,14 +28,14 @@ import com.watabou.utils.DeviceCompat; public class WndTextInput extends Window { - private static final int WIDTH = 120; - private static final int W_LAND_MULTI = 200; //in the specific case of multiline in landscape + private static final int WIDTH = 130; + private static final int W_LAND_EXTRA = 200; //extra width is sometimes used in landscape private static final int MARGIN = 2; private static final int BUTTON_HEIGHT = 16; private TextInput textBox; - public WndTextInput(final String title, final String initialValue, final int maxLength, + public WndTextInput(final String title, final String body, final String initialValue, final int maxLength, final boolean multiLine, final String posTxt, final String negTxt) { super(); @@ -50,17 +49,32 @@ public class WndTextInput extends Window { } final int width; - if (PixelScene.landscape() && multiLine) { - width = W_LAND_MULTI; //more editing space for landscape users + if (PixelScene.landscape() && (multiLine || body != null)) { + width = W_LAND_EXTRA; //more space for landscape users } else { width = WIDTH; } - final RenderedTextBlock txtTitle = PixelScene.renderTextBlock(title, 9); - txtTitle.maxWidth(width); - txtTitle.hardlight(Window.TITLE_COLOR); - txtTitle.setPos((width - txtTitle.width()) / 2, 2); - add(txtTitle); + float pos = 2; + + if (title != null) { + final RenderedTextBlock txtTitle = PixelScene.renderTextBlock(title, 9); + txtTitle.maxWidth(width); + txtTitle.hardlight(Window.TITLE_COLOR); + txtTitle.setPos((width - txtTitle.width()) / 2, 2); + add(txtTitle); + + pos = txtTitle.bottom() + 2 * MARGIN; + } + + if (body != null) { + final RenderedTextBlock txtBody = PixelScene.renderTextBlock(body, 6); + txtBody.maxWidth(width); + txtBody.setPos(0, pos); + add(txtBody); + + pos = txtBody.bottom() + 2 * MARGIN; + } int textSize = (int)PixelScene.uiCamera.zoom * (multiLine ? 6 : 9); textBox = new TextInput(Chrome.get(Chrome.Type.TOAST_WHITE), multiLine, textSize){ @@ -74,8 +88,6 @@ public class WndTextInput extends Window { if (initialValue != null) textBox.setText(initialValue); textBox.setMaxLength(maxLength); - float pos = txtTitle.bottom() + 2 * MARGIN; - //sets different height depending on whether this is a single or multi line input. final float inputHeight; if (multiLine) { diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/utils/DungeonSeed.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/utils/DungeonSeed.java index 97f872813..9e49df047 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/utils/DungeonSeed.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/utils/DungeonSeed.java @@ -26,7 +26,7 @@ import com.watabou.utils.Random; //This class defines the parameters for seeds in ShatteredPD and contains a few convenience methods public class DungeonSeed { - private static long TOTAL_SEEDS = 5429503678976L; //26^9 possible seeds + public static long TOTAL_SEEDS = 5429503678976L; //26^9 possible seeds public static long randomSeed(){ return Random.Long( TOTAL_SEEDS ); @@ -41,8 +41,12 @@ public class DungeonSeed { //Takes a seed code (@@@@@@@@@) and converts it to the equivalent long value public static long convertFromCode( String code ){ - if (code.length() != 9) + //ignore whitespace characters and dashes + code = code.replaceAll("[-\\s]", ""); + + if (code.length() != 9) { throw new IllegalArgumentException("codes must be 9 A-Z characters."); + } long result = 0; for (int i = 8; i >= 0; i--) { @@ -57,12 +61,13 @@ public class DungeonSeed { //Takes a long value and converts it to the equivalent seed code public static String convertToCode( long seed ){ - if (seed < 0 || seed >= TOTAL_SEEDS) + if (seed < 0 || seed >= TOTAL_SEEDS) { throw new IllegalArgumentException("seeds must be within the range [0, TOTAL_SEEDS)"); + } //this almost gives us the right answer, but its 0-p instead of A-Z String interrim = Long.toString(seed, 26); - String result = ""; + StringBuilder result = new StringBuilder(); //so we convert for (int i = 0; i < 9; i++) { @@ -72,21 +77,42 @@ public class DungeonSeed { if (c <= '9') c += 17; //convert 0-9 to A-J else c -= 22; //convert a-p to K-Z - result += c; + result.append(c); } else { - result = 'A' + result; //pad with A (zeroes) until we reach length of 9 + result.insert(0, 'A'); //pad with A (zeroes) until we reach length of 9 } } - return result; + //insert dashes for readability + result.insert(3, '-'); + result.insert(7, '-'); + + return result.toString(); } - //Using this we can let users input 'fun' plaintext seeds and convert them to a long equivalent. - // This is basically the same as string.hashcode except with long, and accounting for overflow - // to ensure the produced seed is always in the range [0, TOTAL_SEEDS) + //Creates a seed from arbitrary user text input public static long convertFromText( String inputText ){ + if (inputText.isEmpty()) return -1; + + //First see if input is a seed code, use that format if it is + try { + return convertFromCode(inputText); + } catch (IllegalArgumentException e){ + + } + + //Then see if input is a number (ignoring spaces), if so parse as a long seed (with overflow) + try { + return Long.parseLong(inputText.replaceAll("\\s", "")) % TOTAL_SEEDS; + } catch (NumberFormatException e){ + + } + + //Finally, if the user has entered unformatted text, convert it to a long seed equivalent + // This is basically the same as string.hashcode except with long, and overflow + // this lets the user input 'fun' seeds, like names or places long total = 0; for (char c : inputText.toCharArray()){ total = 31 * total + c; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndGameInProgress.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndGameInProgress.java index 6e2a85d04..996c00ee2 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndGameInProgress.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndGameInProgress.java @@ -36,6 +36,7 @@ import com.shatteredpixel.shatteredpixeldungeon.ui.Icons; import com.shatteredpixel.shatteredpixeldungeon.ui.RedButton; import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock; import com.shatteredpixel.shatteredpixeldungeon.ui.Window; +import com.shatteredpixel.shatteredpixeldungeon.utils.DungeonSeed; import com.watabou.noosa.Game; import com.shatteredpixel.shatteredpixeldungeon.ui.Button; import com.watabou.utils.Bundle; @@ -70,23 +71,6 @@ public class WndGameInProgress extends Window { title.setRect( 0, 0, WIDTH, 0 ); add(title); - //manually produces debug information about a run, mainly useful for levelgen errors - Button debug = new Button(){ - @Override - protected boolean onLongClick() { - try { - Bundle bundle = FileUtils.bundleFromFile(GamesInProgress.gameFile(slot)); - ShatteredPixelDungeon.scene().addToFront(new WndMessage("_Debug Info:_\n\n" + - "Version: " + Game.version + " (" + Game.versionCode + ")\n" + - "Seed: " + bundle.getLong("seed") + "\n" + - "Challenge Mask: " + info.challenges)); - } catch (IOException ignored) { } - return true; - } - }; - debug.setRect(0, 0, title.imIcon.width(), title.imIcon.height); - add(debug); - if (info.challenges > 0) GAP -= 2; pos = title.bottom() + GAP; @@ -119,6 +103,11 @@ public class WndGameInProgress extends Window { pos += GAP; statSlot( Messages.get(this, "gold"), info.goldCollected ); statSlot( Messages.get(this, "depth"), info.maxDepth ); + if (info.customSeed){ + statSlot( Messages.get(this, "custom_seed"), "_" + DungeonSeed.convertToCode(info.seed) + "_" ); + } else { + statSlot( Messages.get(this, "dungeon_seed"), DungeonSeed.convertToCode(info.seed) ); + } pos += GAP; @@ -175,7 +164,7 @@ public class WndGameInProgress extends Window { add( txt ); txt = PixelScene.renderTextBlock( value, 8 ); - txt.setPos(WIDTH * 0.6f, pos); + txt.setPos(WIDTH * 0.55f, pos); PixelScene.align(txt); add( txt ); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndHero.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndHero.java index 25f72e18c..7d01ae22a 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndHero.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndHero.java @@ -21,7 +21,6 @@ package com.shatteredpixel.shatteredpixeldungeon.windows; -import com.shatteredpixel.shatteredpixeldungeon.Assets; import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon; import com.shatteredpixel.shatteredpixeldungeon.Statistics; @@ -41,12 +40,10 @@ import com.shatteredpixel.shatteredpixeldungeon.ui.StatusPane; import com.shatteredpixel.shatteredpixeldungeon.ui.TalentButton; import com.shatteredpixel.shatteredpixeldungeon.ui.TalentsPane; import com.shatteredpixel.shatteredpixeldungeon.ui.Window; -import com.watabou.gltextures.SmartTexture; -import com.watabou.gltextures.TextureCache; +import com.shatteredpixel.shatteredpixeldungeon.utils.DungeonSeed; import com.watabou.noosa.Gizmo; import com.watabou.noosa.Group; import com.watabou.noosa.Image; -import com.watabou.noosa.TextureFilm; import com.watabou.noosa.ui.Component; import java.util.ArrayList; @@ -188,6 +185,11 @@ public class WndHero extends WndTabbed { statSlot( Messages.get(this, "gold"), Statistics.goldCollected ); statSlot( Messages.get(this, "depth"), Statistics.deepestFloor ); + if (Dungeon.usingCustomSeed){ + statSlot( Messages.get(this, "custom_seed"), "_" + DungeonSeed.convertToCode(Dungeon.seed) + "_" ); + } else { + statSlot( Messages.get(this, "dungeon_seed"), DungeonSeed.convertToCode(Dungeon.seed) ); + } pos += GAP; } @@ -199,7 +201,7 @@ public class WndHero extends WndTabbed { add( txt ); txt = PixelScene.renderTextBlock( value, 8 ); - txt.setPos(WIDTH * 0.6f, pos); + txt.setPos(WIDTH * 0.55f, pos); PixelScene.align(txt); add( txt ); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndRanking.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndRanking.java index 304dc2a1d..1f6730f2a 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndRanking.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndRanking.java @@ -330,7 +330,7 @@ public class WndRanking extends WndTabbed { camera = WndRanking.this.camera; Component badges; - if (Badges.unlocked(false) <= 7){ + if (Badges.totalUnlocked(false) <= 7){ badges = new BadgesList(false); } else { badges = new BadgesGrid(false);