v1.4.0: added functionality to replay daily runs as practise

This commit is contained in:
Evan Debenham
2022-09-14 12:49:28 -04:00
parent 34d5fd2583
commit 168911efda
17 changed files with 122 additions and 63 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -62,7 +62,7 @@ scenes.heroselectscene.daily=Daily Run
scenes.heroselectscene.daily_desc=Every day a new game is available that is the same for everyone! This 'daily run' generates the same dungeon for every person who plays it (so long as they are also playing the same game version).\n\nYou can take as long as you like to complete a daily run, but can only have one active at a time. _Daily runs are not eligible for badges and have their own separate rankings page._\n\nWould you like to start today's daily with your currently selected hero and challenges?
scenes.heroselectscene.daily_yes=Yes
scenes.heroselectscene.daily_no=No
scenes.heroselectscene.daily_unavailable=A new daily run is available every day at midnight UTC
scenes.heroselectscene.daily_repeat=You have already played today's daily. You can replay it if you like, but only as an unranked practice run.\n\nAfter you complete the replay, you will be able to view it from the daily rankings window for a short time before the record is deleted.\n\nWould you like to replay today's daily with your currently selected hero and challenges?
scenes.heroselectscene.daily_unavailable_long=It seems you've started a daily that's in the future! This can happen if you recently changed timezones, or if you changed your system clock. _Your next daily will be available in %d days._
scenes.heroselectscene.daily_existing=You already have a daily run in progress. You must end that run before starting another daily.
scenes.heroselectscene.custom_seed_title=Enter a Custom Seed

View File

@@ -54,6 +54,7 @@ windows.wndgameinprogress.depth=Maximum Depth
windows.wndgameinprogress.dungeon_seed=Dungeon Seed
windows.wndgameinprogress.custom_seed=_Custom Seed_
windows.wndgameinprogress.daily_for=_Daily For_
windows.wndgameinprogress.replay_for=_Replay For_
windows.wndgameinprogress.continue=Continue
windows.wndgameinprogress.erase=Erase
windows.wndgameinprogress.erase_warn_title=Are you sure you want to delete this save?
@@ -73,6 +74,7 @@ windows.wndhero$statstab.depth=Maximum Depth
windows.wndhero$statstab.dungeon_seed=Dungeon Seed
windows.wndhero$statstab.custom_seed=_Custom Seed_
windows.wndhero$statstab.daily_for=_Daily For_
windows.wndhero$statstab.replay_for=_Replay For_
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.
@@ -177,6 +179,7 @@ windows.wndranking$statstab.ascent=Highest Ascent
windows.wndranking$statstab.seed=Dungeon Seed
windows.wndranking$statstab.custom_seed=_Custom Seed_
windows.wndranking$statstab.daily_for=_Daily For_
windows.wndranking$statstab.replay_for=_Replay For_
windows.wndranking$statstab.enemies=Mobs Killed
windows.wndranking$statstab.gold=Gold Collected
windows.wndranking$statstab.food=Food Eaten

View File

@@ -194,6 +194,7 @@ public class Dungeon {
public static int version;
public static boolean daily;
public static boolean dailyReplay;
public static String customSeedText = "";
public static long seed;
@@ -518,6 +519,7 @@ public class Dungeon {
private static final String SEED = "seed";
private static final String CUSTOM_SEED = "custom_seed";
private static final String DAILY = "daily";
private static final String DAILY_REPLAY= "daily_replay";
private static final String CHALLENGES = "challenges";
private static final String MOBS_TO_CHAMPION = "mobs_to_champion";
private static final String HERO = "hero";
@@ -542,6 +544,7 @@ public class Dungeon {
bundle.put( SEED, seed );
bundle.put( CUSTOM_SEED, customSeedText );
bundle.put( DAILY, daily );
bundle.put( DAILY_REPLAY, dailyReplay );
bundle.put( CHALLENGES, challenges );
bundle.put( MOBS_TO_CHAMPION, mobsToChampion );
bundle.put( HERO, hero );
@@ -619,7 +622,7 @@ public class Dungeon {
saveGame( GamesInProgress.curSlot );
saveLevel( GamesInProgress.curSlot );
GamesInProgress.set( GamesInProgress.curSlot, depth, challenges, seed, customSeedText, daily, hero );
GamesInProgress.set( GamesInProgress.curSlot );
}
}
@@ -644,6 +647,7 @@ public class Dungeon {
seed = bundle.contains( SEED ) ? bundle.getLong( SEED ) : DungeonSeed.randomSeed();
customSeedText = bundle.getString( CUSTOM_SEED );
daily = bundle.getBoolean( DAILY );
dailyReplay = bundle.getBoolean( DAILY_REPLAY );
Actor.clear();
Actor.restoreNextID( bundle );
@@ -779,6 +783,7 @@ public class Dungeon {
info.seed = bundle.getLong( SEED );
info.customSeed = bundle.getString( CUSTOM_SEED );
info.daily = bundle.getBoolean( DAILY );
info.dailyReplay = bundle.getBoolean( DAILY_REPLAY );
Hero.preview( info, bundle.getBundle( HERO ) );
Statistics.preview( info, bundle );

View File

@@ -126,28 +126,28 @@ public class GamesInProgress {
}
}
public static void set(int slot, int depth, int challenges, long seed, String customSeed, boolean daily,
Hero hero) {
public static void set(int slot) {
Info info = new Info();
info.slot = slot;
info.depth = depth;
info.challenges = challenges;
info.depth = Dungeon.depth;
info.challenges = Dungeon.challenges;
info.seed = seed;
info.customSeed = customSeed;
info.daily = daily;
info.seed = Dungeon.seed;
info.customSeed = Dungeon.customSeedText;
info.daily = Dungeon.daily;
info.dailyReplay = Dungeon.dailyReplay;
info.level = hero.lvl;
info.str = hero.STR;
info.strBonus = hero.STR() - hero.STR;
info.exp = hero.exp;
info.hp = hero.HP;
info.ht = hero.HT;
info.shld = hero.shielding();
info.heroClass = hero.heroClass;
info.subClass = hero.subClass;
info.armorTier = hero.tier();
info.level = Dungeon.hero.lvl;
info.str = Dungeon.hero.STR;
info.strBonus = Dungeon.hero.STR() - Dungeon.hero.STR;
info.exp = Dungeon.hero.exp;
info.hp = Dungeon.hero.HP;
info.ht = Dungeon.hero.HT;
info.shld = Dungeon.hero.shielding();
info.heroClass = Dungeon.hero.heroClass;
info.subClass = Dungeon.hero.subClass;
info.armorTier = Dungeon.hero.tier();
info.goldCollected = Statistics.goldCollected;
info.maxDepth = Statistics.deepestFloor;
@@ -173,7 +173,8 @@ public class GamesInProgress {
public long seed;
public String customSeed;
public boolean daily;
public boolean dailyReplay;
public int level;
public int str;
public int strBonus;

View File

@@ -68,6 +68,7 @@ public enum Rankings {
public int localWon;
public Record latestDaily;
public Record latestDailyReplay = null; //not stored, only meant to be temp
public LinkedHashMap<Long, Integer> dailyScoreHistory = new LinkedHashMap<>();
public void submit( boolean win, Class cause ) {
@@ -99,6 +100,11 @@ public enum Rankings {
rec.gameID = UUID.randomUUID().toString();
if (rec.daily){
if (Dungeon.dailyReplay){
latestDailyReplay = rec;
return;
}
latestDaily = rec;
if (Dungeon.seed <= DungeonSeed.TOTAL_SEEDS) {
dailyScoreHistory.put(Dungeon.seed, rec.score);
@@ -215,6 +221,7 @@ public enum Rankings {
public static final String SEED = "seed";
public static final String CUSTOM_SEED = "custom_seed";
public static final String DAILY = "daily";
public static final String DAILY_REPLAY = "daily_replay";
public void saveGameData(Record rec){
rec.gameData = new Bundle();
@@ -276,6 +283,7 @@ public enum Rankings {
rec.gameData.put( SEED, Dungeon.seed );
rec.gameData.put( CUSTOM_SEED, Dungeon.customSeedText );
rec.gameData.put( DAILY, Dungeon.daily );
rec.gameData.put( DAILY_REPLAY, Dungeon.dailyReplay );
}
public void loadGameData(Record rec){
@@ -314,10 +322,11 @@ public enum Rankings {
Dungeon.seed = rec.gameData.getLong(SEED);
Dungeon.customSeedText = rec.gameData.getString(CUSTOM_SEED);
Dungeon.daily = rec.gameData.getBoolean(DAILY);
Dungeon.dailyReplay = rec.gameData.getBoolean(DAILY_REPLAY);
} else {
Dungeon.seed = -1;
Dungeon.customSeedText = "";
Dungeon.daily = false;
Dungeon.daily = Dungeon.dailyReplay = false;
}
}

View File

@@ -29,7 +29,6 @@ import com.shatteredpixel.shatteredpixeldungeon.Rankings;
import com.shatteredpixel.shatteredpixeldungeon.SPDSettings;
import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroClass;
import com.shatteredpixel.shatteredpixeldungeon.journal.Document;
import com.shatteredpixel.shatteredpixeldungeon.journal.Journal;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.ui.ActionIndicator;
@@ -126,7 +125,7 @@ public class HeroSelectScene extends PixelScene {
if (GamesInProgress.selectedClass == null) return;
Dungeon.hero = null;
Dungeon.daily = false;
Dungeon.daily = Dungeon.dailyReplay = false;
ActionIndicator.action = null;
InterlevelScene.mode = InterlevelScene.Mode.DESCEND;
@@ -434,12 +433,8 @@ public class HeroSelectScene extends PixelScene {
super.onClick();
long diff = (SPDSettings.lastDaily() + DAY) - Game.realTime;
if (diff > 0){
if (diff > 30*HOUR){
ShatteredPixelDungeon.scene().addToFront(new WndMessage(Messages.get(HeroSelectScene.class, "daily_unavailable_long", (diff / DAY)+1)));
} else {
ShatteredPixelDungeon.scene().addToFront(new WndMessage(Messages.get(HeroSelectScene.class, "daily_unavailable")));
}
if (diff > 24*HOUR){
ShatteredPixelDungeon.scene().addToFront(new WndMessage(Messages.get(HeroSelectScene.class, "daily_unavailable_long", (diff / DAY)+1)));
return;
}
@@ -451,23 +446,31 @@ public class HeroSelectScene extends PixelScene {
}
Image icon = Icons.get(Icons.CALENDAR);
icon.hardlight(0.5f, 1f, 2f);
if (diff <= 0) icon.hardlight(0.5f, 1f, 2f);
else icon.hardlight(1f, 0.5f, 2f);
ShatteredPixelDungeon.scene().addToFront(new WndOptions(
icon,
Messages.get(HeroSelectScene.class, "daily"),
Messages.get(HeroSelectScene.class, "daily_desc"),
diff > 0 ?
Messages.get(HeroSelectScene.class, "daily_repeat") :
Messages.get(HeroSelectScene.class, "daily_desc"),
Messages.get(HeroSelectScene.class, "daily_yes"),
Messages.get(HeroSelectScene.class, "daily_no")){
@Override
protected void onSelect(int index) {
if (index == 0){
long time = Game.realTime - (Game.realTime % DAY);
if (diff <= 0) {
long time = Game.realTime - (Game.realTime % DAY);
//earliest possible daily for v1.3.0 is June 20 2022
//which is 19,163 days after Jan 1 1970
time = Math.max(time, 19_163 * DAY);
//earliest possible daily for v1.4.0 is Sept 10 2022
//which is 19,245 days after Jan 1 1970
time = Math.max(time, 19_245 * DAY);
SPDSettings.lastDaily(time);
SPDSettings.lastDaily(time);
Dungeon.dailyReplay = false;
} else {
Dungeon.dailyReplay = true;
}
Dungeon.hero = null;
Dungeon.daily = true;
@@ -500,11 +503,9 @@ public class HeroSelectScene extends PixelScene {
} else {
text(dateFormat.format(new Date(diff)));
}
textColor(0x888888);
timeToUpdate = Game.realTime + SECOND;
} else {
text(Messages.get(HeroSelectScene.class, "daily"));
textColor(0xFFFFFF);
timeToUpdate = Long.MAX_VALUE;
}
}

View File

@@ -173,7 +173,7 @@ public class RankingsScene extends PixelScene {
public void destroy() {
super.destroy();
//so that opening daily records does not trigger WndDailies opening on future visits
Dungeon.daily = false;
Dungeon.daily = Dungeon.dailyReplay = false;
}
@Override

View File

@@ -204,7 +204,11 @@ public class StartScene extends PixelScene {
}
if (info.daily){
steps.hardlight(0.5f, 1f, 2f);
if (info.dailyReplay){
steps.hardlight(1f, 0.5f, 2f);
} else {
steps.hardlight(0.5f, 1f, 2f);
}
} else if (!info.customSeed.isEmpty()){
steps.hardlight(1f, 1.5f, 0.67f);
}

View File

@@ -146,7 +146,7 @@ public class TitleScene extends PixelScene {
};
btnRankings.icon(Icons.get(Icons.RANKINGS));
add(btnRankings);
Dungeon.daily = false;
Dungeon.daily = Dungeon.dailyReplay = false;
StyledButton btnBadges = new StyledButton(GREY_TR, Messages.get(this, "badges")){
@Override

View File

@@ -280,7 +280,7 @@ public class WelcomeScene extends PixelScene {
FileUtils.deleteFile( Rankings.RANKINGS_FILE );
ShatteredPixelDungeon.reportException(e);
}
Dungeon.daily = false;
Dungeon.daily = Dungeon.dailyReplay = false;
}

View File

@@ -311,36 +311,28 @@ public enum Icons {
icon.frame( icon.texture.uvRectBySize( 40, 72, 8, 8 ) );
break;
case DEPTH:
int ofs = Dungeon.daily ? 16 : (!Dungeon.customSeedText.isEmpty() ? 8 : 0);
icon.frame( icon.texture.uvRectBySize( 48, 64 + ofs, 6, 7 ) );
icon.frame( icon.texture.uvRectBySize( 48, 64 + runTypeOfs(), 6, 7 ) );
break;
case DEPTH_CHASM:
ofs = Dungeon.daily ? 16 : (!Dungeon.customSeedText.isEmpty() ? 8 : 0);
icon.frame( icon.texture.uvRectBySize( 56, 64 + ofs, 7, 7 ) );
icon.frame( icon.texture.uvRectBySize( 56, 64 + runTypeOfs(), 7, 7 ) );
break;
case DEPTH_WATER:
ofs = Dungeon.daily ? 16 : (!Dungeon.customSeedText.isEmpty() ? 8 : 0);
icon.frame( icon.texture.uvRectBySize( 64, 64 + ofs, 7, 7 ) );
icon.frame( icon.texture.uvRectBySize( 64, 64 + runTypeOfs(), 7, 7 ) );
break;
case DEPTH_GRASS:
ofs = Dungeon.daily ? 16 : (!Dungeon.customSeedText.isEmpty() ? 8 : 0);
icon.frame( icon.texture.uvRectBySize( 72, 64 + ofs, 7, 7 ) );
icon.frame( icon.texture.uvRectBySize( 72, 64 + runTypeOfs(), 7, 7 ) );
break;
case DEPTH_DARK:
ofs = Dungeon.daily ? 16 : (!Dungeon.customSeedText.isEmpty() ? 8 : 0);
icon.frame( icon.texture.uvRectBySize( 80, 64 + ofs, 7, 7 ) );
icon.frame( icon.texture.uvRectBySize( 80, 64 + runTypeOfs(), 7, 7 ) );
break;
case DEPTH_LARGE:
ofs = Dungeon.daily ? 16 : (!Dungeon.customSeedText.isEmpty() ? 8 : 0);
icon.frame( icon.texture.uvRectBySize( 88, 64 + ofs, 7, 7 ) );
icon.frame( icon.texture.uvRectBySize( 88, 64 + runTypeOfs(), 7, 7 ) );
break;
case DEPTH_TRAPS:
ofs = Dungeon.daily ? 16 : (!Dungeon.customSeedText.isEmpty() ? 8 : 0);
icon.frame( icon.texture.uvRectBySize( 96, 64 + ofs, 7, 7 ) );
icon.frame( icon.texture.uvRectBySize( 96, 64 + runTypeOfs(), 7, 7 ) );
break;
case DEPTH_SECRETS:
ofs = Dungeon.daily ? 16 : (!Dungeon.customSeedText.isEmpty() ? 8 : 0);
icon.frame( icon.texture.uvRectBySize( 104, 64 + ofs, 7, 7 ) );
icon.frame( icon.texture.uvRectBySize( 104, 64 + runTypeOfs(), 7, 7 ) );
break;
case CHAL_COUNT:
icon.frame( icon.texture.uvRectBySize( 112, 64, 7, 7 ) );
@@ -381,6 +373,20 @@ public enum Icons {
}
return icon;
}
private static int runTypeOfs(){
if (Dungeon.daily){
if (Dungeon.dailyReplay){
return 24;
} else {
return 16;
}
} else if (!Dungeon.customSeedText.isEmpty()){
return 8;
} else {
return 0;
}
}
public static Image get( HeroClass cl ) {
switch (cl) {

View File

@@ -62,6 +62,24 @@ public class WndDailies extends Window {
title.setPos(0, 0);
content.add(title);
if (Rankings.INSTANCE.latestDailyReplay != null){
IconButton replayInfo = new IconButton(Icons.get(Icons.CALENDAR)){
@Override
protected void onClick() {
ShatteredPixelDungeon.scene().addToFront(new WndRanking(Rankings.INSTANCE.latestDailyReplay));
}
@Override
protected void onPointerUp() {
super.onPointerUp();
icon.hardlight(1f, 0.5f, 2f);
}
};
replayInfo.icon().hardlight(1f, 0.5f, 2f);
replayInfo.setRect(WIDTH-16, 0, 16, 16);
add(replayInfo);
}
int top = (int)title.bottom()+3;
RenderedTextBlock day = PixelScene.renderTextBlock(Messages.get(this, "date"), 7);

View File

@@ -104,7 +104,11 @@ public class WndGameInProgress extends Window {
statSlot( Messages.get(this, "gold"), info.goldCollected );
statSlot( Messages.get(this, "depth"), info.maxDepth );
if (info.daily) {
statSlot( Messages.get(this, "daily_for"), "_" + info.customSeed + "_" );
if (info.dailyReplay) {
statSlot(Messages.get(this, "replay_for"), "_" + info.customSeed + "_");
} else {
statSlot(Messages.get(this, "daily_for"), "_" + info.customSeed + "_");
}
} else if (!info.customSeed.isEmpty()){
statSlot( Messages.get(this, "custom_seed"), "_" + info.customSeed + "_" );
} else {
@@ -121,7 +125,7 @@ public class WndGameInProgress extends Window {
GamesInProgress.curSlot = slot;
Dungeon.hero = null;
Dungeon.daily = false;
Dungeon.daily = Dungeon.dailyReplay = false;
ActionIndicator.action = null;
InterlevelScene.mode = InterlevelScene.Mode.CONTINUE;
ShatteredPixelDungeon.switchScene(InterlevelScene.class);

View File

@@ -186,7 +186,11 @@ public class WndHero extends WndTabbed {
statSlot( Messages.get(this, "gold"), Statistics.goldCollected );
statSlot( Messages.get(this, "depth"), Statistics.deepestFloor );
if (Dungeon.daily){
statSlot( Messages.get(this, "daily_for"), "_" + Dungeon.customSeedText + "_" );
if (!Dungeon.dailyReplay) {
statSlot(Messages.get(this, "daily_for"), "_" + Dungeon.customSeedText + "_");
} else {
statSlot(Messages.get(this, "replay_for"), "_" + Dungeon.customSeedText + "_");
}
} else if (!Dungeon.customSeedText.isEmpty()){
statSlot( Messages.get(this, "custom_seed"), "_" + Dungeon.customSeedText + "_" );
} else {

View File

@@ -194,7 +194,11 @@ public class WndRanking extends WndTabbed {
}
if (Dungeon.seed != -1) {
if (Dungeon.daily){
pos = statSlot(this, Messages.get(this, "daily_for"), "_" + Dungeon.customSeedText + "_", pos);
if (Dungeon.dailyReplay) {
pos = statSlot(this, Messages.get(this, "replay_for"), "_" + Dungeon.customSeedText + "_", pos);
} else {
pos = statSlot(this, Messages.get(this, "daily_for"), "_" + Dungeon.customSeedText + "_", pos);
}
} else if (!Dungeon.customSeedText.isEmpty()){
pos = statSlot(this, Messages.get(this, "custom_seed"), "_" + Dungeon.customSeedText + "_", pos);
} else {

View File

@@ -94,7 +94,7 @@ public class WndStartGame extends Window {
GamesInProgress.curSlot = slot;
Dungeon.hero = null;
Dungeon.daily = false;
Dungeon.daily = Dungeon.dailyReplay = false;
ActionIndicator.action = null;
InterlevelScene.mode = InterlevelScene.Mode.DESCEND;