v1.3.0: overhauled scoring system for rankings

This commit is contained in:
Evan Debenham
2022-05-11 22:37:38 -04:00
parent f4b94ad64b
commit e12f246569
30 changed files with 346 additions and 47 deletions

View File

@@ -156,7 +156,7 @@ windows.wndranking.badges=Badges
windows.wndranking$statstab.title=Level %1$d %2$s
windows.wndranking$statstab.talents=Talents
windows.wndranking$statstab.challenges=Challenges
windows.wndranking$statstab.health=Health
windows.wndranking$statstab.score=Score
windows.wndranking$statstab.str=Strength
windows.wndranking$statstab.duration=Game Duration
windows.wndranking$statstab.depth=Maximum Depth
@@ -164,7 +164,6 @@ windows.wndranking$statstab.enemies=Mobs Killed
windows.wndranking$statstab.gold=Gold Collected
windows.wndranking$statstab.food=Food Eaten
windows.wndranking$statstab.alchemy=Items Crafted
windows.wndranking$statstab.ankhs=Ankhs Used
windows.wndresurrect.title=Resurrection
windows.wndresurrect.message=As you perish you can feel your ankh guiding your spirit back toward this world. It's giving you another chance to conquer the dungeon!\n\nYou can bring two of your items with you, but the rest will be left where you perished. Which items will you choose?

View File

@@ -58,6 +58,7 @@ import com.shatteredpixel.shatteredpixeldungeon.levels.CityBossLevel;
import com.shatteredpixel.shatteredpixeldungeon.levels.HallsBossLevel;
import com.shatteredpixel.shatteredpixeldungeon.levels.PrisonBossLevel;
import com.shatteredpixel.shatteredpixeldungeon.levels.PrisonLevel;
import com.shatteredpixel.shatteredpixeldungeon.levels.RegularLevel;
import com.shatteredpixel.shatteredpixeldungeon.levels.SewerBossLevel;
import com.shatteredpixel.shatteredpixeldungeon.levels.SewerLevel;
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.secret.SecretRoom;
@@ -173,6 +174,8 @@ public class Dungeon {
public static SparseArray<ArrayList<Item>> droppedItems;
public static SparseArray<ArrayList<Item>> portedItems;
//first variable is only assigned when game is started, second is updated every time game is saved
public static int initialVersion;
public static int version;
public static long seed;
@@ -180,7 +183,7 @@ public class Dungeon {
public static void init() {
version = Game.versionCode;
initialVersion = version = Game.versionCode;
challenges = SPDSettings.challenges();
mobsToChampion = -1;
@@ -462,7 +465,8 @@ public class Dungeon {
//chance is floors left / scrolls left
return Random.Int(5 - floorThisSet) < asLeftThisSet;
}
private static final String INIT_VER = "init_ver";
private static final String VERSION = "version";
private static final String SEED = "seed";
private static final String CUSTOM_SEED = "custom_seed";
@@ -485,8 +489,8 @@ public class Dungeon {
try {
Bundle bundle = new Bundle();
version = Game.versionCode;
bundle.put( VERSION, version );
bundle.put( INIT_VER, initialVersion );
bundle.put( VERSION, version = Game.versionCode );
bundle.put( SEED, seed );
bundle.put( CUSTOM_SEED, usingCustomSeed );
bundle.put( CHALLENGES, challenges );
@@ -562,6 +566,7 @@ public class Dungeon {
if (hero != null && (hero.isAlive() || WndResurrect.instance != null)) {
Actor.fixTime();
updateLevelExplored();
saveGame( GamesInProgress.curSlot );
saveLevel( GamesInProgress.curSlot );
@@ -578,6 +583,13 @@ public class Dungeon {
Bundle bundle = FileUtils.bundleFromFile( GamesInProgress.gameFile( save ) );
//pre-1.3.0 saves
if (bundle.contains(INIT_VER)){
initialVersion = bundle.getInt( INIT_VER );
} else {
initialVersion = bundle.getInt( VERSION );
}
version = bundle.getInt( VERSION );
seed = bundle.contains( SEED ) ? bundle.getLong( SEED ) : DungeonSeed.randomSeed();
@@ -722,17 +734,28 @@ public class Dungeon {
public static void fail( Class cause ) {
if (WndResurrect.instance == null) {
updateLevelExplored();
Statistics.gameWon = false;
Rankings.INSTANCE.submit( false, cause );
}
}
public static void win( Class cause ) {
updateLevelExplored();
Statistics.gameWon = true;
hero.belongings.identify();
Rankings.INSTANCE.submit( true, cause );
}
public static void updateLevelExplored(){
if (branch == 0 && level instanceof RegularLevel){
Statistics.floorsExplored.put( depth, level.isLevelExplored(depth));
}
}
//default to recomputing based on max hero vision, in case vision just shrank/grew
public static void observe(){
int dist = Math.max(Dungeon.hero.viewDistance, 8);

View File

@@ -30,6 +30,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.bags.Bag;
import com.shatteredpixel.shatteredpixeldungeon.items.potions.Potion;
import com.shatteredpixel.shatteredpixeldungeon.items.quest.CorpseDust;
import com.shatteredpixel.shatteredpixeldungeon.items.rings.Ring;
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.Scroll;
import com.shatteredpixel.shatteredpixeldungeon.journal.Notes;
@@ -74,7 +75,7 @@ public enum Rankings {
rec.armorTier = Dungeon.hero.tier();
rec.herolevel = Dungeon.hero.lvl;
rec.depth = Dungeon.depth;
rec.score = score( win );
rec.score = calculateScore();
Badges.validateHighScore( rec.score );
@@ -114,11 +115,73 @@ public enum Rankings {
return (Statistics.goldCollected + Dungeon.hero.lvl * (win ? 26 : Dungeon.depth ) * 100) * (win ? 2 : 1);
}
//assumes a ranking is loaded, or game is ending
public int calculateScore(){
if (Dungeon.initialVersion > ShatteredPixelDungeon.v1_2_3+1){
Statistics.progressScore = Dungeon.hero.lvl * Statistics.deepestFloor * 65;
Statistics.progressScore = Math.min(Statistics.progressScore, 50_000);
if (Statistics.heldItemValue == 0) {
for (Item i : Dungeon.hero.belongings) {
Statistics.heldItemValue += i.value();
if (i instanceof CorpseDust && Statistics.deepestFloor >= 10){
// in case player kept the corpse dust, for a necromancer run
Statistics.questScores[1] = 2000;
}
}
}
Statistics.treasureScore = Statistics.goldCollected + Statistics.heldItemValue;
Statistics.treasureScore = Math.min(Statistics.treasureScore, 20_000);
int scorePerFloor = Statistics.floorsExplored.size * 50;
for (Boolean b : Statistics.floorsExplored.valueList()){
if (b) Statistics.exploreScore += scorePerFloor;
}
for (int i : Statistics.bossScores){
if (i > 0) Statistics.totalBossScore += i;
}
for (int i : Statistics.questScores){
if (i > 0) Statistics.totalQuestScore += i;
}
Statistics.winMultiplier = 1f;
if (Statistics.amuletObtained) Statistics.winMultiplier += 0.75f;
if (Statistics.gameWon) Statistics.winMultiplier += 0.25f;
if (Statistics.ascended) Statistics.winMultiplier += 0.25f;
//pre v1.3.0 runs have different score calculations
//only progress and treasure score, and they are each up to 50% bigger
//win multiplier is a simple 2x if run was a win, challenge multi is the same as 1.3.0
} else {
Statistics.progressScore = Dungeon.hero.lvl * Statistics.deepestFloor * 100;
Statistics.treasureScore = Math.min(Statistics.goldCollected, 30_000);
Statistics.exploreScore = Statistics.totalBossScore = Statistics.totalQuestScore = 0;
Statistics.winMultiplier = Statistics.gameWon ? 2 : 1;
}
Statistics.chalMultiplier = (float)Math.pow(1.25, Challenges.activeChallenges());
Statistics.chalMultiplier = Math.round(Statistics.chalMultiplier*20f)/20f;
Statistics.totalScore = Statistics.progressScore + Statistics.treasureScore + Statistics.exploreScore
+ Statistics.totalBossScore + Statistics.totalQuestScore;
Statistics.totalScore *= Statistics.winMultiplier * Statistics.chalMultiplier;
return Statistics.totalScore;
}
public static final String HERO = "hero";
public static final String STATS = "stats";
public static final String BADGES = "badges";
public static final String HANDLERS = "handlers";
public static final String CHALLENGES = "challenges";
public static final String GAME_VERSION = "game_version";
public void saveGameData(Record rec){
rec.gameData = new Bundle();
@@ -171,6 +234,8 @@ public enum Rankings {
//save challenges
rec.gameData.put( CHALLENGES, Dungeon.challenges );
rec.gameData.put( GAME_VERSION, Dungeon.initialVersion );
}
public void loadGameData(Record rec){
@@ -197,6 +262,12 @@ public enum Rankings {
Dungeon.challenges = data.getInt(CHALLENGES);
Dungeon.initialVersion = data.getInt(GAME_VERSION);
if (Dungeon.initialVersion < ShatteredPixelDungeon.v1_2_3+1){
Statistics.gameWon = rec.win;
}
rec.score = calculateScore();
}
private static final String RECORDS = "records";
@@ -276,6 +347,7 @@ public enum Rankings {
public Bundle gameData;
public String gameID;
//Note this is for summary purposes, visible score should be re-calculated from game data
public int score;
public String desc(){

View File

@@ -36,12 +36,12 @@ public class ShatteredPixelDungeon extends Game {
//variable constants for specific older versions of shattered, used for data conversion
//versions older than v0.9.2b are no longer supported, and data from them is ignored
public static final int v0_9_2b = 531;
public static final int v0_9_3c = 557; //557 on iOS, 554 on other platforms
public static final int v0_9_2b = 531;
public static final int v0_9_3c = 557; //557 on iOS, 554 on other platforms
public static final int v1_0_3 = 574;
public static final int v1_1_2 = 587;
public static final int v1_2_0 = 609;
public static final int v1_0_3 = 574;
public static final int v1_1_2 = 587;
public static final int v1_2_3 = 627;
public ShatteredPixelDungeon( PlatformSupport platform ) {
super( sceneClass == null ? WelcomeScene.class : sceneClass, platform );

View File

@@ -22,9 +22,10 @@
package com.shatteredpixel.shatteredpixeldungeon;
import com.watabou.utils.Bundle;
import com.watabou.utils.SparseArray;
public class Statistics {
public static int goldCollected;
public static int deepestFloor;
public static int enemiesSlain;
@@ -32,7 +33,22 @@ public class Statistics {
public static int itemsCrafted;
public static int piranhasKilled;
public static int ankhsUsed;
//These are used for score calculation
// some are built incrementally, most are assigned when full score is calculated
public static int progressScore;
public static int heldItemValue;
public static int treasureScore;
public static SparseArray<Boolean> floorsExplored = new SparseArray<>();
public static int exploreScore;
public static int[] bossScores = new int[5];
public static int totalBossScore;
public static int[] questScores = new int[5];
public static int totalQuestScore;
public static float winMultiplier;
public static float chalMultiplier;
public static int totalScore;
//used for hero unlock badges
public static int upgradesUsed;
public static int sneakAttacks;
@@ -47,6 +63,8 @@ public class Statistics {
public static boolean qualifiedForBossChallengeBadge = false;
public static boolean amuletObtained = false;
public static boolean gameWon = false;
public static boolean ascended = false;
public static void reset() {
@@ -57,6 +75,19 @@ public class Statistics {
itemsCrafted = 0;
piranhasKilled = 0;
ankhsUsed = 0;
progressScore = 0;
heldItemValue = 0;
treasureScore = 0;
floorsExplored = new SparseArray<>();
exploreScore = 0;
bossScores = new int[5];
totalBossScore = 0;
questScores = new int[5];
totalQuestScore = 0;
winMultiplier = 1;
chalMultiplier = 1;
totalScore = 0;
upgradesUsed = 0;
sneakAttacks = 0;
@@ -64,12 +95,14 @@ public class Statistics {
spawnersAlive = 0;
duration = 0;
duration = 0;
qualifiedForNoKilling = false;
qualifiedForBossChallengeBadge = false;
amuletObtained = false;
gameWon = false;
ascended = false;
}
@@ -80,6 +113,19 @@ public class Statistics {
private static final String ALCHEMY = "potionsCooked";
private static final String PIRANHAS = "priranhas";
private static final String ANKHS = "ankhsUsed";
private static final String PROG_SCORE = "prog_score";
private static final String ITEM_VAL = "item_val";
private static final String TRES_SCORE = "tres_score";
private static final String FLR_EXPL = "flr_expl";
private static final String EXPL_SCORE = "expl_score";
private static final String BOSS_SCORES = "boss_scores";
private static final String TOT_BOSS = "tot_boss";
private static final String QUEST_SCORES = "quest_scores";
private static final String TOT_QUEST = "tot_quest";
private static final String WIN_MULT = "win_mult";
private static final String CHAL_MULT = "chal_mult";
private static final String TOTAL_SCORE = "total_score";
private static final String UPGRADES = "upgradesUsed";
private static final String SNEAKS = "sneakAttacks";
@@ -92,7 +138,9 @@ public class Statistics {
private static final String NO_KILLING_QUALIFIED = "qualifiedForNoKilling";
private static final String BOSS_CHALLENGE_QUALIFIED= "qualifiedForBossChallengeBadge";
private static final String AMULET = "amuletObtained";
private static final String AMULET = "amuletObtained";
private static final String WON = "won";
private static final String ASCENDED = "ascended";
public static void storeInBundle( Bundle bundle ) {
bundle.put( GOLD, goldCollected );
@@ -102,6 +150,23 @@ public class Statistics {
bundle.put( ALCHEMY, itemsCrafted );
bundle.put( PIRANHAS, piranhasKilled );
bundle.put( ANKHS, ankhsUsed );
bundle.put( PROG_SCORE, progressScore );
bundle.put( ITEM_VAL, heldItemValue );
bundle.put( TRES_SCORE, treasureScore );
for (int i = 1; i < 26; i++){
if (floorsExplored.containsKey(i)){
bundle.put( FLR_EXPL+i, floorsExplored.get(i) );
}
}
bundle.put( EXPL_SCORE, exploreScore );
bundle.put( BOSS_SCORES, bossScores );
bundle.put( TOT_BOSS, totalBossScore );
bundle.put( QUEST_SCORES,questScores );
bundle.put( TOT_QUEST, totalQuestScore );
bundle.put( WIN_MULT, winMultiplier );
bundle.put( CHAL_MULT, chalMultiplier );
bundle.put( TOTAL_SCORE, totalScore );
bundle.put( UPGRADES, upgradesUsed );
bundle.put( SNEAKS, sneakAttacks );
@@ -112,10 +177,11 @@ public class Statistics {
bundle.put( DURATION, duration );
bundle.put(NO_KILLING_QUALIFIED, qualifiedForNoKilling);
bundle.put(BOSS_CHALLENGE_QUALIFIED, qualifiedForBossChallengeBadge);
bundle.put( AMULET, amuletObtained );
bundle.put( WON, gameWon );
bundle.put( ASCENDED, ascended );
}
public static void restoreFromBundle( Bundle bundle ) {
@@ -126,6 +192,26 @@ public class Statistics {
itemsCrafted = bundle.getInt( ALCHEMY );
piranhasKilled = bundle.getInt( PIRANHAS );
ankhsUsed = bundle.getInt( ANKHS );
progressScore = bundle.getInt( PROG_SCORE );
heldItemValue = bundle.getInt( ITEM_VAL );
treasureScore = bundle.getInt( TRES_SCORE );
floorsExplored.clear();
for (int i = 1; i < 26; i++){
if (bundle.contains( FLR_EXPL+i )){
floorsExplored.put(i, bundle.getBoolean( FLR_EXPL+i ));
}
}
exploreScore = bundle.getInt( EXPL_SCORE );
if (bundle.contains( BOSS_SCORES )) bossScores = bundle.getIntArray( BOSS_SCORES );
else bossScores = new int[5];
totalBossScore = bundle.getInt( TOT_BOSS );
if (bundle.contains( QUEST_SCORES ))questScores = bundle.getIntArray( QUEST_SCORES );
else questScores = new int[5];
totalQuestScore = bundle.getInt( TOT_QUEST );
winMultiplier = bundle.getFloat( WIN_MULT );
chalMultiplier = bundle.getFloat( CHAL_MULT );
totalScore = bundle.getInt( TOTAL_SCORE );
upgradesUsed = bundle.getInt( UPGRADES );
sneakAttacks = bundle.getInt( SNEAKS );
@@ -140,6 +226,8 @@ public class Statistics {
qualifiedForBossChallengeBadge = bundle.getBoolean( BOSS_CHALLENGE_QUALIFIED );
amuletObtained = bundle.getBoolean( AMULET );
gameWon = bundle.getBoolean( WON );
ascended = bundle.getBoolean( ASCENDED );
}
public static void preview( GamesInProgress.Info info, Bundle bundle ){

View File

@@ -1062,6 +1062,7 @@ public class Hero extends Char {
});
ready();
} else {
Statistics.ascended = true;
Badges.silentValidateHappyEnd();
Dungeon.win( Amulet.class );
Dungeon.deleteGame( GamesInProgress.curSlot, true );

View File

@@ -545,6 +545,7 @@ public class DM300 extends Mob {
if (Statistics.qualifiedForBossChallengeBadge){
Badges.validateBossChallengeCompleted();
}
Statistics.bossScores[2] += 3000;
LloydsBeacon beacon = Dungeon.hero.belongings.getItem(LloydsBeacon.class);
if (beacon != null) {
@@ -653,6 +654,9 @@ public class DM300 extends Mob {
Char ch = Actor.findChar(i);
if (ch != null && !(ch instanceof DM300)){
Buff.prolong( ch, Paralysis.class, Dungeon.isChallenged(Challenges.STRONGER_BOSSES) ? 5 : 3 );
if (ch == Dungeon.hero){
Statistics.bossScores[2] -= 100;
}
}
}

View File

@@ -524,6 +524,7 @@ public class DwarfKing extends Mob {
if (Statistics.qualifiedForBossChallengeBadge){
Badges.validateBossChallengeCompleted();
}
Statistics.bossScores[3] += 4000;
Dungeon.level.unseal();
@@ -570,6 +571,14 @@ public class DwarfKing extends Mob {
{
state = HUNTING;
}
@Override
protected void zap() {
if (enemy == Dungeon.hero){
Statistics.bossScores[3] -= 400;
}
super.zap();
}
}
public static class DKGolem extends Golem {

View File

@@ -23,6 +23,7 @@ package com.shatteredpixel.shatteredpixeldungeon.actors.mobs;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.Statistics;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Freezing;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Blindness;
@@ -249,7 +250,10 @@ public abstract class Elemental extends Mob {
@Override
public void die(Object cause) {
super.die(cause);
if (alignment == Alignment.ENEMY) Dungeon.level.drop( new Embers(), pos ).sprite.drop();
if (alignment == Alignment.ENEMY) {
Dungeon.level.drop( new Embers(), pos ).sprite.drop();
Statistics.questScores[1] = 2000;
}
}
@Override

View File

@@ -68,7 +68,10 @@ public class Goo extends Mob {
int max = (HP*2 <= HT) ? 12 : 8;
if (pumpedUp > 0) {
pumpedUp = 0;
Statistics.qualifiedForBossChallengeBadge = false;
if (enemy == Dungeon.hero) {
Statistics.qualifiedForBossChallengeBadge = false;
Statistics.bossScores[0] -= 100;
}
return Random.NormalIntRange( min*3, max*3 );
} else {
return Random.NormalIntRange( min, max );
@@ -98,6 +101,7 @@ public class Goo extends Mob {
if (Dungeon.level.water[pos] && HP < HT) {
HP += healInc;
Statistics.bossScores[0] -= 10;
Statistics.qualifiedForBossChallengeBadge = false;
LockedFloor lock = Dungeon.hero.buff(LockedFloor.class);
@@ -216,7 +220,10 @@ public class Goo extends Mob {
boolean result = super.attack( enemy, dmgMulti, dmgBonus, accMulti );
if (pumpedUp > 0) {
pumpedUp = 0;
Statistics.qualifiedForBossChallengeBadge = false;
if (enemy == Dungeon.hero) {
Statistics.qualifiedForBossChallengeBadge = false;
Statistics.bossScores[0] -= 100;
}
}
return result;
}
@@ -272,6 +279,8 @@ public class Goo extends Mob {
if (Statistics.qualifiedForBossChallengeBadge){
Badges.validateBossChallengeCompleted();
}
Statistics.bossScores[0] += 1050; //Goo has a 50 point gimme
Statistics.bossScores[0] = Math.min(1000, Statistics.bossScores[0]);
yell( Messages.get(this, "defeated") );
}

View File

@@ -127,6 +127,7 @@ public class Pylon extends Mob {
if (ch == Dungeon.hero) {
Statistics.qualifiedForBossChallengeBadge = false;
Statistics.bossScores[2] -= 100;
if (!ch.isAlive()) {
Dungeon.fail(DM300.class);
GLog.n(Messages.get(Electricity.class, "ondeath"));

View File

@@ -22,6 +22,7 @@
package com.shatteredpixel.shatteredpixeldungeon.actors.mobs;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.Statistics;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Blob;
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.ToxicGas;
@@ -101,6 +102,7 @@ public class RotHeart extends Mob {
public void die(Object cause) {
super.die(cause);
Dungeon.level.drop( new Rotberry.Seed(), pos ).sprite.drop();
Statistics.questScores[1] = 2000;
}
@Override

View File

@@ -213,6 +213,7 @@ public class Tengu extends Mob {
if (Statistics.qualifiedForBossChallengeBadge){
Badges.validateBossChallengeCompleted();
}
Statistics.bossScores[1] += 2000;
LloydsBeacon beacon = Dungeon.hero.belongings.getItem(LloydsBeacon.class);
if (beacon != null) {
@@ -618,6 +619,7 @@ public class Tengu extends Mob {
if (ch == Dungeon.hero){
Statistics.qualifiedForBossChallengeBadge = false;
Statistics.bossScores[1] -= 100;
if (!ch.isAlive()) {
Dungeon.fail(Tengu.class);
@@ -850,6 +852,7 @@ public class Tengu extends Mob {
}
if (ch == Dungeon.hero){
Statistics.qualifiedForBossChallengeBadge = false;
Statistics.bossScores[1] -= 100;
}
if (Dungeon.level.flamable[cell]){
@@ -1034,6 +1037,7 @@ public class Tengu extends Mob {
if (ch == Dungeon.hero){
Statistics.qualifiedForBossChallengeBadge = false;
Statistics.bossScores[1] -= 100;
if (!ch.isAlive()) {
Dungeon.fail(Tengu.class);
GLog.n(Messages.get(Electricity.class, "ondeath"));

View File

@@ -99,7 +99,7 @@ public class Warlock extends Mob implements Callback {
//used so resistances can differentiate between melee and magical attacks
public static class DarkBolt{}
private void zap() {
protected void zap() {
spend( TIME_TO_ZAP );
if (hit( this, enemy, true )) {

View File

@@ -220,6 +220,9 @@ public class YogDzewa extends Mob {
} else {
ch.damage(Random.NormalIntRange(20, 30), new Eye.DeathGaze());
}
if (ch == Dungeon.hero){
Statistics.bossScores[4] -= 500;
}
if (Dungeon.level.heroFOV[pos]) {
ch.sprite.flash();
@@ -446,7 +449,7 @@ public class YogDzewa extends Mob {
public void aggro(Char ch) {
for (Mob mob : (Iterable<Mob>)Dungeon.level.mobs.clone()) {
if (Dungeon.level.distance(pos, mob.pos) <= 4 &&
(mob instanceof Larva || mob instanceof RipperDemon)) {
(mob instanceof Larva || mob instanceof YogRipper || mob instanceof YogEye || mob instanceof YogScorpio)) {
mob.aggro(ch);
}
}
@@ -457,7 +460,7 @@ public class YogDzewa extends Mob {
public void die( Object cause ) {
for (Mob mob : (Iterable<Mob>)Dungeon.level.mobs.clone()) {
if (mob instanceof Larva || mob instanceof RipperDemon) {
if (mob instanceof Larva || mob instanceof YogRipper || mob instanceof YogEye || mob instanceof YogScorpio) {
mob.die( cause );
}
}
@@ -471,6 +474,7 @@ public class YogDzewa extends Mob {
} else {
Statistics.qualifiedForBossChallengeBadge = false;
}
Statistics.bossScores[4] += 5000 + 1250*Statistics.spawnersAlive;
Dungeon.level.unseal();
super.die( cause );

View File

@@ -24,6 +24,7 @@ package com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Badges;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.Statistics;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
import com.shatteredpixel.shatteredpixeldungeon.items.BrokenSeal;
@@ -120,6 +121,7 @@ public class Blacksmith extends NPC {
Quest.completed = true;
Quest.reforged = false;
Statistics.questScores[2] = 3000;
}
} else {
@@ -140,6 +142,7 @@ public class Blacksmith extends NPC {
Quest.completed = true;
Quest.reforged = false;
Statistics.questScores[2] = 3000;
}
}

View File

@@ -23,6 +23,7 @@ package com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.Statistics;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.FetidRat;
@@ -339,6 +340,7 @@ public class Ghost extends NPC {
GLog.n( Messages.get(Ghost.class, "find_me") );
Sample.INSTANCE.play( Assets.Sounds.GHOST );
processed = true;
Statistics.questScores[0] = 1000;
}
}

View File

@@ -22,6 +22,7 @@
package com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.Statistics;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Golem;
@@ -247,7 +248,8 @@ public class Imp extends NPC {
public static void complete() {
reward = null;
completed = true;
Statistics.questScores[3] = 4000;
Notes.remove( Notes.Landmark.IMP );
}

View File

@@ -22,6 +22,7 @@
package com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.Statistics;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
@@ -344,6 +345,7 @@ public class Wandmaker extends NPC {
wand2 = null;
Notes.remove( Notes.Landmark.WANDMAKER );
Statistics.questScores[1] = 2000;
}
}
}

View File

@@ -74,6 +74,7 @@ public class Heap implements Bundlable {
public ItemSprite sprite;
public boolean seen = false;
public boolean haunted = false;
public boolean autoExplored = false; //used to determine if this heap should count for exploration bonus
public LinkedList<Item> items = new LinkedList<>();
@@ -403,6 +404,7 @@ public class Heap implements Bundlable {
private static final String TYPE = "type";
private static final String ITEMS = "items";
private static final String HAUNTED = "haunted";
private static final String AUTO_EXPLORED = "auto_explored";
@SuppressWarnings("unchecked")
@Override
@@ -427,7 +429,7 @@ public class Heap implements Bundlable {
}
haunted = bundle.getBoolean( HAUNTED );
autoExplored = bundle.getBoolean( AUTO_EXPLORED );
}
@Override
@@ -437,6 +439,7 @@ public class Heap implements Bundlable {
bundle.put( TYPE, type.toString() );
bundle.put( ITEMS, items );
bundle.put( HAUNTED, haunted );
bundle.put( AUTO_EXPLORED, autoExplored );
}
}

View File

@@ -801,6 +801,7 @@ public class CavesBossLevel extends Level {
//took damage while DM-300 was supercharged
Statistics.qualifiedForBossChallengeBadge = false;
}
Statistics.bossScores[2] -= 200;
if ( !ch.isAlive()) {
Dungeon.fail(DM300.class);
GLog.n(Messages.get(Electricity.class, "ondeath"));

View File

@@ -1250,6 +1250,10 @@ public abstract class Level implements Bundlable {
}
}
public boolean isLevelExplored( int depth ){
return false;
}
public int distance( int a, int b ) {
int ax = a % width();

View File

@@ -25,11 +25,14 @@ import com.shatteredpixel.shatteredpixeldungeon.Bones;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Blob;
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.SacrificialFire;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.GoldenMimic;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mimic;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Statue;
import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
import com.shatteredpixel.shatteredpixeldungeon.items.Heap;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
@@ -38,13 +41,17 @@ import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.DriedRose;
import com.shatteredpixel.shatteredpixeldungeon.items.food.SmallRation;
import com.shatteredpixel.shatteredpixeldungeon.items.journal.GuidePage;
import com.shatteredpixel.shatteredpixeldungeon.items.keys.GoldenKey;
import com.shatteredpixel.shatteredpixeldungeon.items.keys.Key;
import com.shatteredpixel.shatteredpixeldungeon.journal.Document;
import com.shatteredpixel.shatteredpixeldungeon.journal.Journal;
import com.shatteredpixel.shatteredpixeldungeon.journal.Notes;
import com.shatteredpixel.shatteredpixeldungeon.levels.builders.Builder;
import com.shatteredpixel.shatteredpixeldungeon.levels.builders.FigureEightBuilder;
import com.shatteredpixel.shatteredpixeldungeon.levels.builders.LoopBuilder;
import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter;
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.Room;
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.secret.SecretRoom;
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.special.MagicalFireRoom;
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.special.PitRoom;
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.special.ShopRoom;
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.special.SpecialRoom;
@@ -561,7 +568,57 @@ public abstract class RegularLevel extends Level {
return super.fallCell( false );
}
@Override
public boolean isLevelExplored( int depth ) {
//A level is considered fully explored if:
//There are no levelgen heaps which are undiscovered, in an openable container, or which contain keys
for (Heap h : heaps.valueList()){
if (h.autoExplored) continue;
if (!h.seen || (h.type != Heap.Type.HEAP && h.type != Heap.Type.FOR_SALE && h.type != Heap.Type.CRYSTAL_CHEST)){
return false;
}
for (Item i : h.items){
if (i instanceof Key){
return false;
}
}
}
//There is no magical fire or sacrificial fire
for (Blob b : blobs.values()){
if (b.volume > 0 && (b instanceof MagicalFireRoom.EternalFire || b instanceof SacrificialFire)){
return false;
}
}
//There are no statues or mimics (unless they were made allies)
for (Mob m : mobs.toArray(new Mob[0])){
if (m.alignment != Char.Alignment.ALLY && (m instanceof Statue || m instanceof Mimic)){
return false;
}
}
//There are no barricades, locked doors, or hidden doors
for (int i = 0; i < length; i++){
if (map[i] == Terrain.BARRICADE || map[i] == Terrain.LOCKED_DOOR || map[i] == Terrain.SECRET_DOOR){
return false;
}
}
//There are no unused keys for this depth in the journal
for (Notes.KeyRecord rec : Notes.getRecords(Notes.KeyRecord.class)){
if (rec.depth() == depth){
return false;
}
}
//Note that it is NOT required for the player to see every tile or discover every trap.
return true;
}
@Override
public void storeInBundle( Bundle bundle ) {
super.storeInBundle( bundle );

View File

@@ -125,7 +125,10 @@ public class CrystalChoiceRoom extends SpecialRoom {
Generator.Category.RING,
Generator.Category.ARTIFACT
));
level.drop(hidden, level.pointToCell(room2.center())).type = Heap.Type.CHEST;
Heap chest = level.drop(hidden, level.pointToCell(room2.center()));
chest.type = Heap.Type.CHEST;
//opening the chest is optional, so it doesn't count for exploration bonus
chest.autoExplored = true;
level.addItemToSpawn( new CrystalKey( Dungeon.depth ) );

View File

@@ -97,7 +97,10 @@ public class PoisonDartTrap extends Trap {
finalTarget.damage(dmg, trap);
if (finalTarget == Dungeon.hero){
//for the poison dart traps in the Tengu fight
Statistics.qualifiedForBossChallengeBadge = false;
if (Dungeon.depth == 10) {
Statistics.qualifiedForBossChallengeBadge = false;
Statistics.bossScores[1] -= 100;
}
if (!finalTarget.isAlive()) {
Dungeon.fail(trap.getClass());
}

View File

@@ -922,6 +922,8 @@ public class GameScene extends PixelScene {
public static void add( Heap heap ) {
if (scene != null) {
//heaps that aren't added as part of levelgen don't count for exploration bonus
heap.autoExplored = true;
scene.addHeapSprite( heap );
}
}

View File

@@ -23,7 +23,6 @@ package com.shatteredpixel.shatteredpixeldungeon.scenes;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Badges;
import com.shatteredpixel.shatteredpixeldungeon.Challenges;
import com.shatteredpixel.shatteredpixeldungeon.Chrome;
import com.shatteredpixel.shatteredpixeldungeon.GamesInProgress;
import com.shatteredpixel.shatteredpixeldungeon.Rankings;
@@ -32,7 +31,6 @@ import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon;
import com.shatteredpixel.shatteredpixeldungeon.effects.BannerSprites;
import com.shatteredpixel.shatteredpixeldungeon.effects.Fireball;
import com.shatteredpixel.shatteredpixeldungeon.journal.Document;
import com.shatteredpixel.shatteredpixeldungeon.messages.Languages;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.ui.Archs;
import com.shatteredpixel.shatteredpixeldungeon.ui.Icons;
@@ -40,7 +38,6 @@ import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock;
import com.shatteredpixel.shatteredpixeldungeon.ui.StyledButton;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndError;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndHardNotification;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndMessage;
import com.watabou.glwrap.Blending;
import com.watabou.noosa.Camera;
import com.watabou.noosa.ColorBlock;
@@ -50,10 +47,12 @@ import com.watabou.noosa.audio.Music;
import com.watabou.utils.FileUtils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
public class WelcomeScene extends PixelScene {
private static final int LATEST_UPDATE = ShatteredPixelDungeon.v1_2_0;
private static final int LATEST_UPDATE = 630;
@Override
public void create() {
@@ -219,6 +218,7 @@ public class WelcomeScene extends PixelScene {
ShatteredPixelDungeon.reportException(e);
}
}
Collections.sort(Rankings.INSTANCE.records, Rankings.scoreComparator);
Rankings.INSTANCE.save();
} catch (Exception e) {
//if we encounter a fatal error, then just clear the rankings

View File

@@ -268,7 +268,7 @@ public class v1_X_Changes {
"Several recipes have also been buffed, in addition to the cost reductions:\n\n" +
"_- Scroll of Foresight_ duration up to 400 from 250\n" +
"_- Scroll of Dread_ now grants 1/2 exp for defeated enemies\n" +
"_- Potion of Shrouding Fog_ gas quantity increased bt 50%\n\n" +
"_- Potion of Shrouding Fog_ gas quantity increased by 50%\n\n" +
"_-_ Items and effects which create water now douse fire\n\n" +
"_- Caustic Brew_ damage per turn increased by 1\n" +
"_- Infernal and Blizzard Brew_ now start their gas in a 3x3 AOE\n" +

View File

@@ -225,27 +225,24 @@ public class WndRanking extends WndTabbed {
pos += GAP;
//TODO score breakdown page!
pos = statSlot( this, "Score", Integer.toString( Statistics.totalScore ), pos );
pos += GAP;
int strBonus = Dungeon.hero.STR() - Dungeon.hero.STR;
if (strBonus > 0) pos = statSlot(this, Messages.get(this, "str"), Dungeon.hero.STR + " + " + strBonus, pos);
else if (strBonus < 0) pos = statSlot(this, Messages.get(this, "str"), Dungeon.hero.STR + " - " + -strBonus, pos );
else pos = statSlot(this, Messages.get(this, "str"), Integer.toString(Dungeon.hero.STR), pos);
pos = statSlot( this, Messages.get(this, "health"), Integer.toString( Dungeon.hero.HT ), pos );
pos += GAP;
pos = statSlot( this, Messages.get(this, "duration"), Integer.toString( (int)Statistics.duration ), pos );
pos += GAP;
pos = statSlot( this, Messages.get(this, "depth"), Integer.toString( Statistics.deepestFloor ), pos );
pos += GAP;
pos = statSlot( this, Messages.get(this, "enemies"), Integer.toString( Statistics.enemiesSlain ), pos );
pos = statSlot( this, Messages.get(this, "gold"), Integer.toString( Statistics.goldCollected ), pos );
pos += GAP;
pos = statSlot( this, Messages.get(this, "food"), Integer.toString( Statistics.foodEaten ), pos );
pos = statSlot( this, Messages.get(this, "alchemy"), Integer.toString( Statistics.itemsCrafted ), pos );
pos = statSlot( this, Messages.get(this, "ankhs"), Integer.toString( Statistics.ankhsUsed ), pos );
}
private float statSlot( Group parent, String label, String value, float pos ) {
@@ -255,7 +252,7 @@ public class WndRanking extends WndTabbed {
parent.add( txt );
txt = PixelScene.renderTextBlock( value, 7 );
txt.setPos(WIDTH * 0.7f, pos);
txt.setPos(WIDTH * 0.6f, pos);
PixelScene.align(txt);
parent.add( txt );