v1.3.0: implemented rankings support for daily runs

This commit is contained in:
Evan Debenham
2022-06-22 14:27:46 -04:00
parent 4f4a3db3af
commit 49c93b68a5
6 changed files with 254 additions and 18 deletions

View File

@@ -194,6 +194,21 @@ public class Bundle {
}
}
public long[] getLongArray( String key ) {
try {
JSONArray array = data.getJSONArray( key );
int length = array.length();
long[] result = new long[length];
for (int i=0; i < length; i++) {
result[i] = array.getLong( i );
}
return result;
} catch (JSONException e) {
Game.reportException(e);
return null;
}
}
public float[] getFloatArray( String key ) {
try {
JSONArray array = data.getJSONArray( key );
@@ -386,6 +401,18 @@ public class Bundle {
}
}
public void put( String key, long[] array ) {
try {
JSONArray jsonArray = new JSONArray();
for (int i=0; i < array.length; i++) {
jsonArray.put( i, array[i] );
}
data.put( key, jsonArray );
} catch (JSONException e) {
Game.reportException(e);
}
}
public void put( String key, float[] array ) {
try {
JSONArray jsonArray = new JSONArray();

View File

@@ -21,6 +21,11 @@ windows.wndclass.mastery=Mastery
windows.wndcombo.title=choose a combo move
windows.wnddailies.title=Daily History
windows.wnddailies.date=Date
windows.wnddailies.score=Score
windows.wnddocument.missing=page missing
windows.wndenergizeitem.prompt=Energize an Item

View File

@@ -46,6 +46,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.UUID;
public enum Rankings {
@@ -61,16 +62,17 @@ public enum Rankings {
public int totalNumber;
public int wonNumber;
//The number of runs which are only present locally, not in the cloud
public int localTotal;
public int localWon;
public Record latestDaily;
public LinkedHashMap<Long, Integer> dailyScoreHistory = new LinkedHashMap<>();
public void submit( boolean win, Class cause ) {
load();
//TODO need separate storage for daily data
//when loading data, make sure to check for latestDaily errors and correct
if (Dungeon.daily){
return;
}
Record rec = new Record();
rec.cause = cause;
@@ -87,6 +89,7 @@ public enum Rankings {
}
rec.score = calculateScore();
rec.customSeed = Dungeon.customSeedText;
rec.daily = Dungeon.daily;
Badges.validateHighScore( rec.score );
@@ -94,6 +97,13 @@ public enum Rankings {
rec.gameID = UUID.randomUUID().toString();
if (rec.daily){
latestDaily = rec;
dailyScoreHistory.put(Dungeon.seed, rec.score);
save();
return;
}
records.add( rec );
Collections.sort( records, scoreComparator );
@@ -308,6 +318,10 @@ public enum Rankings {
private static final String TOTAL = "total";
private static final String WON = "won";
public static final String LATEST_DAILY = "latest_daily";
public static final String DAILY_HISTORY_DATES = "daily_history_dates";
public static final String DAILY_HISTORY_SCORES = "daily_history_scores";
public void save() {
Bundle bundle = new Bundle();
bundle.put( RECORDS, records );
@@ -315,6 +329,19 @@ public enum Rankings {
bundle.put( TOTAL, totalNumber );
bundle.put( WON, wonNumber );
bundle.put(LATEST_DAILY, latestDaily);
long[] dates = new long[dailyScoreHistory.size()];
int[] scores = new int[dailyScoreHistory.size()];
int i = 0;
for (Long l : dailyScoreHistory.keySet()){
dates[i] = l;
scores[i] = dailyScoreHistory.get(l);
i++;
}
bundle.put(DAILY_HISTORY_DATES, dates);
bundle.put(DAILY_HISTORY_SCORES, scores);
try {
FileUtils.bundleToFile( RANKINGS_FILE, bundle);
} catch (IOException e) {
@@ -353,6 +380,23 @@ public enum Rankings {
}
}
if (bundle.contains(LATEST_DAILY)){
latestDaily = (Record) bundle.get(LATEST_DAILY);
dailyScoreHistory.clear();
int[] scores = bundle.getIntArray(DAILY_HISTORY_SCORES);
int i = 0;
long latestDate = 0;
for (long date : bundle.getLongArray(DAILY_HISTORY_DATES)){
dailyScoreHistory.put(date, scores[i]);
if (date > latestDate) latestDate = date;
i++;
}
if (latestDate > SPDSettings.lastDaily()){
SPDSettings.lastDaily(latestDate);
}
}
} catch (IOException e) {
}
}
@@ -370,6 +414,7 @@ public enum Rankings {
private static final String DATA = "gameData";
private static final String ID = "gameID";
private static final String SEED = "custom_seed";
private static final String DAILY = "daily";
public Class cause;
public boolean win;
@@ -387,6 +432,7 @@ public enum Rankings {
public int score;
public String customSeed;
public boolean daily;
public String desc(){
if (win){
@@ -419,6 +465,7 @@ public enum Rankings {
win = bundle.getBoolean( WIN );
score = bundle.getInt( SCORE );
customSeed = bundle.getString( SEED );
daily = bundle.getBoolean( DAILY );
heroClass = bundle.getEnum( CLASS, HeroClass.class );
armorTier = bundle.getInt( TIER );
@@ -441,6 +488,7 @@ public enum Rankings {
bundle.put( WIN, win );
bundle.put( SCORE, score );
bundle.put( SEED, customSeed );
bundle.put( DAILY, daily );
bundle.put( CLASS, heroClass );
bundle.put( TIER, armorTier );
@@ -456,6 +504,7 @@ public enum Rankings {
public static final Comparator<Record> scoreComparator = new Comparator<Rankings.Record>() {
@Override
public int compare( Record lhs, Record rhs ) {
//this covers custom seeded runs and dailies
if (rhs.customSeed.isEmpty() && !lhs.customSeed.isEmpty()){
return +1;
} else if (lhs.customSeed.isEmpty() && !rhs.customSeed.isEmpty()){

View File

@@ -31,9 +31,11 @@ import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSprite;
import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet;
import com.shatteredpixel.shatteredpixeldungeon.ui.Archs;
import com.shatteredpixel.shatteredpixeldungeon.ui.ExitButton;
import com.shatteredpixel.shatteredpixeldungeon.ui.IconButton;
import com.shatteredpixel.shatteredpixeldungeon.ui.Icons;
import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock;
import com.shatteredpixel.shatteredpixeldungeon.ui.Window;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndDailies;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndError;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndRanking;
import com.watabou.noosa.BitmapText;
@@ -139,6 +141,26 @@ public class RankingsScene extends PixelScene {
btnExit.setPos( Camera.main.width - btnExit.width(), 0 );
add( btnExit );
int left = 0;
if (Rankings.INSTANCE.latestDaily != null) {
IconButton btnDailies = new IconButton(Icons.CALENDAR.get()) {
@Override
protected void onClick() {
ShatteredPixelDungeon.scene().addToFront(new WndDailies());
}
@Override
protected void onPointerUp() {
icon.hardlight(0.5f, 1f, 2f);
}
};
btnDailies.icon().hardlight(0.5f, 1f, 2f);
btnDailies.setRect( left, 0, 20, 20 );
left += 20;
add(btnDailies);
}
fadeIn();
}
@@ -158,7 +180,7 @@ public class RankingsScene extends PixelScene {
private Rankings.Record rec;
protected ItemSprite shield;
protected Image shield;
private Flare flare;
private BitmapText position;
private RenderedTextBlock desc;
@@ -190,7 +212,7 @@ public class RankingsScene extends PixelScene {
int odd = pos % 2;
if (rec.win) {
shield.view( ItemSpriteSheet.AMULET, null );
shield.copy( new ItemSprite(ItemSpriteSheet.AMULET, null) );
position.hardlight( TEXT_WIN[odd] );
desc.hardlight( TEXT_WIN[odd] );
depth.hardlight( TEXT_WIN[odd] );
@@ -211,14 +233,18 @@ public class RankingsScene extends PixelScene {
}
if (rec.ascending){
shield.view( ItemSpriteSheet.AMULET, null );
shield.copy( new ItemSprite(ItemSpriteSheet.AMULET, null) );
shield.hardlight(0.4f, 0.4f, 0.7f);
}
}
if (!rec.customSeed.isEmpty()){
shield.view( ItemSpriteSheet.SEED_SUNGRASS, null );
if (rec.daily){
shield.copy( Icons.get(Icons.CALENDAR) );
shield.hardlight(0.5f, 1f, 2f);
} else if (!rec.customSeed.isEmpty()){
shield.copy( Icons.get(Icons.SEED) );
shield.hardlight(1f, 1.5f, 0.67f);
}
if (rec.herolevel != 0){
@@ -239,7 +265,7 @@ public class RankingsScene extends PixelScene {
super.createChildren();
shield = new ItemSprite( ItemSpriteSheet.TOMB, null );
shield = new Image(new ItemSprite( ItemSpriteSheet.TOMB, null ));
add( shield );
position = new BitmapText( PixelScene.pixelFont);

View File

@@ -0,0 +1,128 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2022 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.windows;
import com.shatteredpixel.shatteredpixeldungeon.Rankings;
import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.scenes.PixelScene;
import com.shatteredpixel.shatteredpixeldungeon.ui.IconButton;
import com.shatteredpixel.shatteredpixeldungeon.ui.Icons;
import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock;
import com.shatteredpixel.shatteredpixeldungeon.ui.ScrollPane;
import com.shatteredpixel.shatteredpixeldungeon.ui.Window;
import com.watabou.noosa.ColorBlock;
import com.watabou.noosa.ui.Component;
import java.text.DateFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
public class WndDailies extends Window {
private static final int WIDTH = 115;
private static final int HEIGHT = 144;
public WndDailies(){
resize(WIDTH, HEIGHT);
ScrollPane pane = new ScrollPane(new Component());
add(pane);
pane.setRect(0, 0, WIDTH, HEIGHT);
Component content = pane.content();
IconTitle title = new IconTitle(Icons.CALENDAR.get(), Messages.get(this, "title"));
title.imIcon.hardlight(0.5f, 1f, 2f);
title.setRect(0, 0, WIDTH, 0);
title.setPos(0, 0);
content.add(title);
int top = (int)title.bottom()+3;
RenderedTextBlock day = PixelScene.renderTextBlock(Messages.get(this, "date"), 7);
day.hardlight(TITLE_COLOR);
day.setPos(0, top);
content.add(day);
RenderedTextBlock score = PixelScene.renderTextBlock(Messages.get(this, "score"), 7);
score.hardlight(TITLE_COLOR);
score.setPos(WIDTH - score.width(), top);
content.add(score);
top = (int) score.bottom() + 6;
NumberFormat num = NumberFormat.getInstance(Locale.US);
DateFormat format = DateFormat.getDateInstance();
format.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = new Date();
//reverse order so that latest dailies are on top
ArrayList<Long> dates = new ArrayList<>(Rankings.INSTANCE.dailyScoreHistory.keySet());
Collections.reverse(dates);
boolean first = Rankings.INSTANCE.latestDaily != null;
for (long l : dates) {
if (first) top += 2;
ColorBlock sep = new ColorBlock(WIDTH, 1, 0xFF000000);
sep.y = top - 3 - (first ? 2 : 0);
content.add(sep);
date.setTime(l);
day = PixelScene.renderTextBlock(format.format(date), 7);
day.setPos(0, top);
content.add(day);
if (first){
IconButton latestInfo = new IconButton(Icons.INFO.get()){
@Override
protected void onClick() {
ShatteredPixelDungeon.scene().addToFront(new WndRanking(Rankings.INSTANCE.latestDaily));
}
};
latestInfo.setRect(day.right()+2, top - 5, 16, 16);
content.add(latestInfo);
}
score = PixelScene.renderTextBlock(num.format(Rankings.INSTANCE.dailyScoreHistory.get(l)), 7);
score.setPos(WIDTH - score.width(), top);
content.add(score);
top = (int) day.bottom() + 6;
if (first){
top += 2;
first = false;
}
}
content.setRect(0, 0, WIDTH, top);
pane.setRect(0, 0, WIDTH, HEIGHT);
}
}

View File

@@ -217,9 +217,9 @@ public class WndRanking extends WndTabbed {
}
if (Dungeon.seed != -1) {
if (Dungeon.daily){
pos = statSlot(this, Messages.get(this, "daily_for"), "_" + DungeonSeed.convertToCode(Dungeon.seed) + "_", pos);
pos = statSlot(this, Messages.get(this, "daily_for"), "_" + Dungeon.customSeedText + "_", pos);
} else if (!Dungeon.customSeedText.isEmpty()){
pos = statSlot(this, Messages.get(this, "custom_seed"), "_" + DungeonSeed.convertToCode(Dungeon.seed) + "_", pos);
pos = statSlot(this, Messages.get(this, "custom_seed"), "_" + Dungeon.customSeedText + "_", pos);
} else {
pos = statSlot(this, Messages.get(this, "seed"), DungeonSeed.convertToCode(Dungeon.seed), pos);
}
@@ -236,7 +236,8 @@ public class WndRanking extends WndTabbed {
int buttontop = HEIGHT - 16;
if (Dungeon.seed != -1 && (DeviceCompat.isDebug() || Badges.isUnlocked(Badges.Badge.VICTORY))){
if (Dungeon.seed != -1 && !Dungeon.daily &&
(DeviceCompat.isDebug() || Badges.isUnlocked(Badges.Badge.VICTORY))){
final Image icon = Icons.get(Icons.SEED);
RedButton btnSeed = new RedButton(Messages.get(this, "copy_seed")){
@Override