v0.4.3: implement seeds into levelgen (not currently user enterable)
This commit is contained in:
@@ -22,6 +22,7 @@
|
||||
package com.watabou.noosa;
|
||||
|
||||
import com.watabou.noosa.particles.Emitter;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -275,7 +276,7 @@ public class Group extends Gizmo {
|
||||
|
||||
public synchronized Gizmo random() {
|
||||
if (length > 0) {
|
||||
return members.get( (int)(Math.random() * length) );
|
||||
return members.get( Random.Int(length) );
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -75,6 +75,10 @@ public class Bundle {
|
||||
public int getInt( String key ) {
|
||||
return data.optInt( key );
|
||||
}
|
||||
|
||||
public long getLong( String key ) {
|
||||
return data.optLong( key );
|
||||
}
|
||||
|
||||
public float getFloat( String key ) {
|
||||
return (float)data.optDouble( key, 0.0 );
|
||||
@@ -238,6 +242,14 @@ public class Bundle {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void put( String key, long value ) {
|
||||
try {
|
||||
data.put( key, value );
|
||||
} catch (JSONException e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void put( String key, float value ) {
|
||||
try {
|
||||
|
||||
@@ -26,34 +26,64 @@ import java.util.HashMap;
|
||||
|
||||
public class Random {
|
||||
|
||||
public static float Float( float min, float max ) {
|
||||
return (float)(min + Math.random() * (max - min));
|
||||
private static java.util.Random rand = new java.util.Random();
|
||||
|
||||
public static void seed( ){
|
||||
rand = new java.util.Random();
|
||||
}
|
||||
|
||||
public static float Float( float max ) {
|
||||
return (float)(Math.random() * max);
|
||||
|
||||
public static void seed( long seed ){
|
||||
rand.setSeed(seed);
|
||||
}
|
||||
|
||||
|
||||
//returns a uniformly distributed float in the range [0, 1)
|
||||
public static float Float() {
|
||||
return (float)Math.random();
|
||||
return rand.nextFloat();
|
||||
}
|
||||
|
||||
|
||||
//returns a uniformly distributed float in the range [0, max)
|
||||
public static float Float( float max ) {
|
||||
return Float() * max;
|
||||
}
|
||||
|
||||
//returns a uniformly distributed float in the range [min, max)
|
||||
public static float Float( float min, float max ) {
|
||||
return min + Float(max - min);
|
||||
}
|
||||
|
||||
//returns a uniformly distributed int in the range [0, max)
|
||||
public static int Int( int max ) {
|
||||
return max > 0 ? (int)(Math.random() * max) : 0;
|
||||
return max > 0 ? rand.nextInt(max) : 0;
|
||||
}
|
||||
|
||||
|
||||
//returns a uniformly distributed int in the range [min, max)
|
||||
public static int Int( int min, int max ) {
|
||||
return min + (int)(Math.random() * (max - min));
|
||||
return min + Int(max - min);
|
||||
}
|
||||
|
||||
|
||||
//returns a uniformly distributed int in the range [min, max]
|
||||
public static int IntRange( int min, int max ) {
|
||||
return min + (int)(Math.random() * (max - min + 1));
|
||||
return min + Int(max - min + 1);
|
||||
}
|
||||
|
||||
|
||||
//returns a triangularly distributed int in the range [min, max]
|
||||
public static int NormalIntRange( int min, int max ) {
|
||||
return min + (int)((Math.random() + Math.random()) * (max - min + 1) / 2f);
|
||||
return min + (int)((Float() + Float()) * (max - min + 1) / 2f);
|
||||
}
|
||||
|
||||
|
||||
//returns a uniformly distributed long in the range [-2^63, 2^63)
|
||||
public static long Long() {
|
||||
return rand.nextLong();
|
||||
}
|
||||
|
||||
//returns a uniformly distributed long in the range [0, max)
|
||||
public static long Long( long max ) {
|
||||
long result = Long();
|
||||
if (result < 0) result += Long.MAX_VALUE;
|
||||
return result % max;
|
||||
}
|
||||
|
||||
//returns an index from chances, the probability of each index is the weight values in changes
|
||||
public static int chances( float[] chances ) {
|
||||
|
||||
int length = chances.length;
|
||||
@@ -76,6 +106,7 @@ public class Random {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
//returns a key element from chances, the probability of each key is the weight value it maps to
|
||||
public static <K> K chances( HashMap<K,Float> chances ) {
|
||||
|
||||
int size = chances.size();
|
||||
@@ -102,12 +133,12 @@ public class Random {
|
||||
}
|
||||
|
||||
public static int index( Collection<?> collection ) {
|
||||
return (int)(Math.random() * collection.size());
|
||||
return Int(collection.size());
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static<T> T oneOf( T... array ) {
|
||||
return array[(int)(Math.random() * array.length)];
|
||||
public static<T> T oneOf(T... array ) {
|
||||
return array[Int(array.length)];
|
||||
}
|
||||
|
||||
public static<T> T element( T[] array ) {
|
||||
@@ -115,7 +146,7 @@ public class Random {
|
||||
}
|
||||
|
||||
public static<T> T element( T[] array, int max ) {
|
||||
return array[(int)(Math.random() * max)];
|
||||
return array[Int(max)];
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
@@ -58,6 +58,7 @@ import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.scenes.StartScene;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.ui.QuickSlotButton;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.utils.BArray;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.utils.DungeonSeed;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.windows.WndResurrect;
|
||||
import com.watabou.noosa.Game;
|
||||
import com.watabou.utils.Bundlable;
|
||||
@@ -70,7 +71,6 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
|
||||
public class Dungeon {
|
||||
@@ -136,18 +136,30 @@ public class Dungeon {
|
||||
public static SparseArray<ArrayList<Item>> droppedItems;
|
||||
|
||||
public static int version;
|
||||
|
||||
public static long seed;
|
||||
|
||||
public static void init() {
|
||||
|
||||
version = Game.versionCode;
|
||||
challenges = ShatteredPixelDungeon.challenges();
|
||||
|
||||
seed = DungeonSeed.randomSeed();
|
||||
|
||||
Actor.clear();
|
||||
Actor.resetNextID();
|
||||
|
||||
Scroll.initLabels();
|
||||
Potion.initColors();
|
||||
Ring.initGems();
|
||||
Random.seed( seed );
|
||||
|
||||
Scroll.initLabels();
|
||||
Potion.initColors();
|
||||
Ring.initGems();
|
||||
|
||||
transmutation = Random.IntRange( 6, 14 );
|
||||
|
||||
Room.shuffleTypes();
|
||||
|
||||
Random.seed();
|
||||
|
||||
Statistics.reset();
|
||||
Journal.reset();
|
||||
@@ -162,8 +174,6 @@ public class Dungeon {
|
||||
|
||||
for (limitedDrops a : limitedDrops.values())
|
||||
a.count = 0;
|
||||
|
||||
transmutation = Random.IntRange( 6, 14 );
|
||||
|
||||
chapters = new HashSet<Integer>();
|
||||
|
||||
@@ -171,8 +181,6 @@ public class Dungeon {
|
||||
Wandmaker.Quest.reset();
|
||||
Blacksmith.Quest.reset();
|
||||
Imp.Quest.reset();
|
||||
|
||||
Room.shuffleTypes();
|
||||
|
||||
Generator.initArtifacts();
|
||||
hero = new Hero();
|
||||
@@ -275,6 +283,19 @@ public class Dungeon {
|
||||
level.reset();
|
||||
switchLevel( level, level.entrance );
|
||||
}
|
||||
|
||||
public static long seedCurDepth(){
|
||||
return seedForDepth(depth);
|
||||
}
|
||||
|
||||
public static long seedForDepth(int depth){
|
||||
Random.seed( seed );
|
||||
for (int i = 0; i < depth; i ++)
|
||||
Random.Long(); //we don't care about these values, just need to go through them
|
||||
long result = Random.Long();
|
||||
Random.seed();
|
||||
return result;
|
||||
}
|
||||
|
||||
public static boolean shopOnLevel() {
|
||||
return depth == 6 || depth == 11 || depth == 16;
|
||||
@@ -375,6 +396,7 @@ public class Dungeon {
|
||||
private static final String RN_DEPTH_FILE = "ranger%d.dat";
|
||||
|
||||
private static final String VERSION = "version";
|
||||
private static final String SEED = "seed";
|
||||
private static final String CHALLENGES = "challenges";
|
||||
private static final String HERO = "hero";
|
||||
private static final String GOLD = "gold";
|
||||
@@ -420,6 +442,7 @@ public class Dungeon {
|
||||
|
||||
version = Game.versionCode;
|
||||
bundle.put( VERSION, version );
|
||||
bundle.put( SEED, seed );
|
||||
bundle.put( CHALLENGES, challenges );
|
||||
bundle.put( HERO, hero );
|
||||
bundle.put( GOLD, gold );
|
||||
@@ -519,6 +542,8 @@ public class Dungeon {
|
||||
|
||||
version = bundle.getInt( VERSION );
|
||||
|
||||
seed = bundle.contains( SEED ) ? bundle.getLong( SEED ) : DungeonSeed.randomSeed();
|
||||
|
||||
Generator.reset();
|
||||
|
||||
Actor.restoreNextID( bundle );
|
||||
|
||||
@@ -173,6 +173,8 @@ public abstract class Level implements Bundlable {
|
||||
|
||||
public void create() {
|
||||
|
||||
Random.seed( Dungeon.seedCurDepth() );
|
||||
|
||||
setupSize();
|
||||
PathFinder.setMapSize(width(), height());
|
||||
passable = new boolean[length()];
|
||||
@@ -275,6 +277,8 @@ public abstract class Level implements Bundlable {
|
||||
|
||||
createMobs();
|
||||
createItems();
|
||||
|
||||
Random.seed();
|
||||
}
|
||||
|
||||
protected void setupSize(){
|
||||
|
||||
@@ -407,7 +407,7 @@ public abstract class RegularLevel extends Level {
|
||||
split( new Rect( rect.left, vh, rect.right, rect.bottom ) );
|
||||
|
||||
} else
|
||||
if ((Math.random() <= (minRoomSize * minRoomSize / rect.square()) && w <= maxRoomSize && h <= maxRoomSize) || w < minRoomSize || h < minRoomSize) {
|
||||
if ((Random.Float() <= (minRoomSize * minRoomSize / rect.square()) && w <= maxRoomSize && h <= maxRoomSize) || w < minRoomSize || h < minRoomSize) {
|
||||
|
||||
rooms.add( (Room)new Room().set( rect ) );
|
||||
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2015 Oleg Dolya
|
||||
*
|
||||
* Shattered Pixel Dungeon
|
||||
* Copyright (C) 2014-2016 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 <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
package com.shatteredpixel.shatteredpixeldungeon.utils;
|
||||
|
||||
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 randomSeed(){
|
||||
return Random.Long( TOTAL_SEEDS );
|
||||
}
|
||||
|
||||
//Seed codes take the form @@@-@@@-@@@ where @ is any letter from A to Z (only uppercase)
|
||||
//This is effectively a base-26 number system, therefore 26^9 unique seeds are possible.
|
||||
|
||||
//Seed codes exist to make sharing and inputting seeds easier
|
||||
//ZZZ-ZZZ-ZZZ is much easier to enter and share than 5,429,503,678,975
|
||||
|
||||
|
||||
//Takes a seed code (@@@@@@@@@) and converts it to the equivalent long value
|
||||
public static long convertFromCode( String code ){
|
||||
if (code.length() != 9)
|
||||
throw new IllegalArgumentException("codes must be 9 A-Z characters.");
|
||||
|
||||
long result = 0;
|
||||
for (int i = 8; i >= 0; i--) {
|
||||
char c = code.charAt(i);
|
||||
if (c > 'Z' || c < 'A')
|
||||
throw new IllegalArgumentException("codes must be 9 A-Z characters.");
|
||||
|
||||
result += (c - 65) * Math.pow(26, (8 - i));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//Takes a long value and converts it to the equivalent seed code
|
||||
public static String convertToCode( long seed ){
|
||||
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 = "";
|
||||
|
||||
//so we convert
|
||||
for (int i = 0; i < 9; i++) {
|
||||
|
||||
if (i < interrim.length()){
|
||||
char c = interrim.charAt(i);
|
||||
if (c <= '9') c += 17; //convert 0-9 to A-J
|
||||
else c -= 22; //convert a-p to K-Z
|
||||
|
||||
result += c;
|
||||
|
||||
} else {
|
||||
result = 'A' + result; //pad with A (zeroes) until we reach length of 9
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//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)
|
||||
public static long convertFromText( String inputText ){
|
||||
long total = 0;
|
||||
for (char c : inputText.toCharArray()){
|
||||
total = 31 * total + c;
|
||||
}
|
||||
if (total < 0) total += Long.MAX_VALUE;
|
||||
total %= TOTAL_SEEDS;
|
||||
return total;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user