mirror of
				https://github.com/zenorogue/hyperrogue.git
				synced 2025-10-31 14:02:59 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1086 lines
		
	
	
		
			36 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1086 lines
		
	
	
		
			36 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Hyperbolic Rogue -- Achievements
 | |
| // Copyright (C) 2011-2019 Zeno Rogue, see 'hyper.cpp' for details
 | |
| 
 | |
| /** \file achievements.cpp 
 | |
|  *  \brief This file implements routines related to achievements and leaderboards
 | |
|  *
 | |
|  *  This routines are general, i.e., not necessarily Steam-specific.
 | |
|  */
 | |
| 
 | |
| #include "hyper.h"
 | |
| namespace hr {
 | |
| 
 | |
| #if HDR
 | |
| #define NUMLEADER 90
 | |
| #endif
 | |
| 
 | |
| EX bool test_achievements = false;
 | |
| 
 | |
| EX bool offlineMode = false;
 | |
| 
 | |
| EX const char* leadernames[NUMLEADER] = {
 | |
|   "Score", "Diamonds", "Gold", "Spice", "Rubies", "Elixirs",
 | |
|   "Shards100", "Totems", "Daisies", "Statues", "Feathers", "Sapphires",
 | |
|   "Hyperstones", "Time to Win-71", "Turns to Win-71",
 | |
|   "Time to 10 Hyperstones-120", "Turns to 10 Hyperstones-120", "Orbs of Yendor",
 | |
|   "Fern Flowers", 
 | |
|   "Royal Jellies", "Powerstones", "Silver", "Wine", "Emeralds", "Grimoires",
 | |
|   "Holy Grails", "Red Gems", "Pirate Treasures",
 | |
|   "Shmup Score", "Shmup Time to Win", "Shmup Knife to Win",
 | |
|   "Bomberbird Eggs", // 31
 | |
|   "Ambers", // 32
 | |
|   "Pearls", // 33
 | |
|   "Hypersian Rugs", // 34
 | |
|   "Garnets", // 35
 | |
|   "Princess Challenge", // 36
 | |
|   "Ivory Figurines", // 37
 | |
|   "Elemental Gems", // 38
 | |
|   "Onyxes", // 39
 | |
|   "Yendor Challenge", // 40
 | |
|   "Pure Tactics Mode", // 41
 | |
|   "Mutant Saplings", // 42
 | |
|   "Fulgurites", // 43
 | |
|   "Shmup Score 2p", // 44
 | |
|   "Coop Shmup Time to Win", // 45
 | |
|   "Black Lotuses", // 46
 | |
|   "Mutant Fruits", // 47
 | |
|   "White Dove Feathers", // 48
 | |
|   "Pure Tactics Mode (shmup)", // 49
 | |
|   "Pure Tactics Mode (2p)", // 50
 | |
|   "Corals", // 51
 | |
|   "Thornless Roses", // 52
 | |
|   "Chaos Mode", // 53
 | |
|   "Tortoise points", // 54
 | |
|   "Dragon Scales", // 55
 | |
|   "Apples", // 56
 | |
|   "Heptagonal Mode", // 57
 | |
|   "Sunken Treasures", // 58
 | |
|   "Ancient Jewelry", // 59
 | |
|   "Golden Eggs", // 60
 | |
|   "Multiplayer Score", // 61
 | |
|   "Statistics", // 62
 | |
|   "Halloween", // 63
 | |
|   "Amethysts", // 64
 | |
|   "Slime Molds", // 65
 | |
|   "Dodecahedra", // 66
 | |
|   "Green Grass", // 67
 | |
|   "Spinel", // 68
 | |
|   "Orb Strategy Score", // 69
 | |
|   "Real time to Win-OS", // 70
 | |
|   "Turns to Win-OS", // 71
 | |
|   "Ancient Weapons", // 72
 | |
|   "Forgotten Relics", // 73
 | |
|   "Lava Lilies", // 74
 | |
|   "Turquoises", // 75
 | |
|   "Chrysoberyls", // 76
 | |
|   "Tasty Jellies", // 77
 | |
|   "Tiger's Eyes", // 78
 | |
|   "Torbernites", // 79
 | |
|   "Meteorites", // 80
 | |
|   "Racing Official Track", // 81
 | |
|   "Gold Balls", // 82
 | |
|   "Lazurite Figurines", // 83
 | |
|   "Water Lilies", // 84
 | |
|   "Capon Stones", // 85
 | |
|   "Crystal Dice", // 86
 | |
|   "Crossbow (bull)", // 87
 | |
|   "Crossbow (geodesic)", // 88
 | |
|   "Crossbow (geometric)", // 89
 | |
|   };
 | |
| 
 | |
| #if HDR
 | |
| #define LB_PRINCESS 36
 | |
| #define LB_STATISTICS 62
 | |
| #define LB_HALLOWEEN 63
 | |
| #define LB_YENDOR_CHALLENGE 40
 | |
| #define LB_PURE_TACTICS 41
 | |
| #define LB_PURE_TACTICS_SHMUP 49
 | |
| #define LB_PURE_TACTICS_COOP 50
 | |
| #define LB_RACING 81
 | |
| #endif
 | |
| 
 | |
| EX void achievement_init();
 | |
| EX string myname();
 | |
| EX void achievement_close();
 | |
| EX void achievement_pump();
 | |
| 
 | |
| /** gain the given achievement.
 | |
|  * @param s name of the achievement, e.g., DIAMOND1
 | |
|  * @param flags one of the constants from namespace rg. The achievement is only awarded if special modes are matched exactly.
 | |
|  */
 | |
| EX void achievement_gain(const char* s, char flags IS(0));
 | |
| 
 | |
| EX bool haveLeaderboard(int id);
 | |
| EX int get_currentscore(int id);
 | |
| EX void set_priority_board(int id);
 | |
| EX int get_sync_status();
 | |
| EX bool score_loaded(int id);
 | |
| EX int score_default(int id);
 | |
| EX void improveItemScores();
 | |
| EX void upload_score(int id, int v);
 | |
| 
 | |
| EX string achievementMessage[3];
 | |
| EX int achievementTimer;
 | |
| /** achievements received this game */
 | |
| EX vector<string> achievementsReceived;
 | |
| 
 | |
| /** Returns true if the given achievement cannot be obtained in the current mode.
 | |
|  *  @param flags Mode requested by the achievement. 
 | |
|  */
 | |
| EX bool wrongMode(char flags) {
 | |
|   if(cheater) return true;
 | |
|   if(casual) return true;
 | |
|   if(flags == rg::global) return false;
 | |
|   if(flags == rg::fail) return true;
 | |
| 
 | |
|   if(flags != rg::special_geometry && flags != rg::special_geometry_nicewalls) {
 | |
|     if(!BITRUNCATED) return true;
 | |
|     if(geometry != gNormal) return true;
 | |
|     if(disksize) return true;
 | |
|     }
 | |
|   if(ineligible_starting_land && !flags) return true;
 | |
|   if(use_custom_land_list) return true;
 | |
| 
 | |
|   if(shmup::on != (flags == rg::shmup || flags == rg::racing)) return true;
 | |
|   if(racing::on != (flags == rg::racing)) return true;
 | |
|   if((!!dual::state) != (flags == rg::dualmode)) return true;
 | |
| #if CAP_DAILY
 | |
|   if(daily::on != (flags == rg::daily)) return true;
 | |
| #endif
 | |
|   if(randomPatternsMode) return true;
 | |
|   if(yendor::on) return true;
 | |
|   if(peace::on) return true;
 | |
|   if(tactic::on) return true;
 | |
| #if CAP_TOUR
 | |
|   if(tour::on) return true;
 | |
| #endif
 | |
|   eLandStructure dls = lsNiceWalls;
 | |
|   if(flags == rg::princess && !princess::challenge) return true;
 | |
|   if(flags == rg::special_geometry || flags == rg::princess)
 | |
|     dls = lsSingle;
 | |
|   if(flags == rg::chaos)
 | |
|     dls = lsChaos;
 | |
|   /* in the official racing achievements, the tracks are saved maps anyway */
 | |
|   if(flags == rg::racing)
 | |
|     dls = land_structure;
 | |
| 
 | |
|   if(land_structure != dls) return true;
 | |
|   if(shmup::on && vid.creature_scale != 1) return true;
 | |
|   if(numplayers() > 1 && !multi::friendly_fire) return true;
 | |
|   if(numplayers() > 1 && multi::pvp_mode) return true;
 | |
|   if(numplayers() > 1 && multi::split_screen) return true;
 | |
|   if((numplayers() > 1) != (flags == rg::multi)) return true;
 | |
|   return false;
 | |
|   }
 | |
| 
 | |
| EX set<string> got_achievements;
 | |
| 
 | |
| EX void achievement_gain_once(const string& s, char flags IS(0)) {
 | |
|   LATE(achievement_gain_once(s, flags));
 | |
|   if(got_achievements.count(s)) return;
 | |
|   if(wrongMode(flags)) {
 | |
|     if(test_achievements) println(hlog, "wrong mode for achievement: ", s);
 | |
|     else return;
 | |
|     }
 | |
|   got_achievements.insert(s);
 | |
|   achievement_gain(s.c_str(), flags);
 | |
|   }
 | |
| 
 | |
| namespace rg {
 | |
|   char check(bool b, char val = special_geometry) { return b ? val : fail; }
 | |
|   }
 | |
| 
 | |
| EX char specgeom_zebra() { return rg::check(geometry == gZebraQuotient && !disksize && BITRUNCATED && firstland == laDesert); }
 | |
| EX char specgeom_lovasz() { return rg::check(geometry == gKleinQuartic && variation == eVariation::untruncated && gp::param == gp::loc(1,1) && !disksize && in_lovasz()); }
 | |
| EX char specgeom_halloween() { return rg::check((geometry == gSphere || geometry == gElliptic) && BITRUNCATED && !disksize && firstland == laHalloween); }
 | |
| EX char specgeom_heptagonal() { return rg::check(PURE && geometry == gNormal && !disksize, rg::special_geometry_nicewalls); }
 | |
| EX char specgeom_euclid_gen() { return rg::check(geometry == gEuclid && !disksize && firstland == laMirrorOld); }
 | |
| EX char specgeom_crystal1() { return rg::check(PURE && cryst && ginf[gCrystal].sides == 8 && ginf[gCrystal].vertex == 4 && !crystal::used_compass_inside && !disksize && firstland == laCamelot); }
 | |
| EX char specgeom_crystal2() { return rg::check(BITRUNCATED && cryst && ginf[gCrystal].sides == 8 && ginf[gCrystal].vertex == 3 && !crystal::used_compass_inside && !disksize && firstland == laCamelot); }
 | |
| 
 | |
| EX vector<std::function<char()>> all_specgeom_checks = { specgeom_zebra, specgeom_lovasz, specgeom_halloween, specgeom_heptagonal, specgeom_crystal1, specgeom_crystal2, specgeom_euclid_gen };
 | |
| 
 | |
| EX char any_specgeom() {
 | |
|   for(auto chk: all_specgeom_checks) if(chk() != rg::fail) return chk();
 | |
|   return rg::fail;
 | |
|   }
 | |
| 
 | |
| EX void achievement_log(const char* s, char flags) {
 | |
| 
 | |
|   if(wrongMode(flags)) {
 | |
|     if(test_achievements) println(hlog, "wrong mode for achievement: ", s);
 | |
|     return;
 | |
|     }
 | |
| 
 | |
|   if(test_achievements) {
 | |
|     println(hlog, "got achievement:", s);
 | |
|     return;
 | |
|     }
 | |
|   
 | |
|   for(int i=0; i<isize(achievementsReceived); i++)
 | |
|     if(achievementsReceived[i] == s) return;
 | |
|   achievementsReceived.push_back(s);
 | |
|   
 | |
| #if CAP_SAVE
 | |
|   remove_emergency_save();
 | |
| 
 | |
|   FILE *f = fopen(scorefile.c_str(), "at");
 | |
|   if(!f) return;
 | |
|   
 | |
|   int t = (int) (time(NULL) - timerstart);
 | |
| 
 | |
|   time_t timer = time(NULL);
 | |
|   char buf[128]; strftime(buf, 128, "%c", localtime(&timer));
 | |
| 
 | |
|   fprintf(f, "ACHIEVEMENT %s turns: %d time: %d at: %d ver: %s c: %d date: %s\n",
 | |
|     s, turncount, t, int(timerstart), VER, anticheat::certify(s, turncount, t, (int) timerstart, 0), buf);
 | |
| 
 | |
|   fclose(f);
 | |
| #endif
 | |
|   }
 | |
| 
 | |
| #ifndef LEADER
 | |
| #define LEADER "Unknown"
 | |
| #define LEADERFULL "Unknown"
 | |
| #endif
 | |
| 
 | |
| #if !CAP_ACHIEVE
 | |
| void achievement_init() {}
 | |
| string myname() { return "Rogue"; }
 | |
| void achievement_close() {}
 | |
| // gain the achievement with the given name.
 | |
| // flags: 'e' - for Euclidean, 's' - for Shmup, '7' - for heptagonal
 | |
| // Only awarded if special modes are matched exactly.
 | |
| void achievement_gain(const char* s, char flags) {
 | |
|   achievement_log(s, flags);
 | |
|   }
 | |
| void achievement_pump() {}
 | |
| EX int get_sync_status() { return 0; }
 | |
| EX void set_priority_board(int) { }
 | |
| #endif
 | |
| 
 | |
| // gain the achievement for collecting a number of 'it'.
 | |
| EX void achievement_collection(eItem it) {
 | |
|   achievement_collection2(it, items[it]);
 | |
|   }
 | |
| 
 | |
| EX void achievement_collection2(eItem it, int q) {
 | |
|   if(cheater && !test_achievements) return;
 | |
|   if(casual && !test_achievements) return;
 | |
|   if(randomPatternsMode) return;
 | |
|   LATE( achievement_collection2(it, q); )
 | |
| 
 | |
|   if(it == itTreat && q == 50)
 | |
|     achievement_gain("HALLOWEEN1", specgeom_halloween());
 | |
| 
 | |
|   if(it == itTreat && q == 100)
 | |
|     achievement_gain("HALLOWEEN2", specgeom_halloween());
 | |
| 
 | |
|   if(q == 1) {
 | |
|     if(it == itDiamond) achievement_gain("DIAMOND1");
 | |
|     if(it == itRuby) achievement_gain("RUBY1");
 | |
|     if(it == itHyperstone) achievement_gain("HYPER1");
 | |
|     if(it == itGold) achievement_gain("GOLD1");
 | |
|     if(it == itStatue) achievement_gain("STATUE1");
 | |
|     if(it == itShard) achievement_gain("MIRROR1");
 | |
|     if(it == itBone) achievement_gain("TOTEM1");
 | |
|     if(it == itSpice) achievement_gain("SPICE1");
 | |
|     if(it == itElixir) achievement_gain("ELIXIR1");
 | |
|     if(it == itHell) achievement_gain("DAISY1");
 | |
|     if(it == itFeather) achievement_gain("FEATHER1");
 | |
|     if(it == itSapphire) achievement_gain("SAPPHIRE1");
 | |
|     if(it == itFernFlower) achievement_gain("FERN1");
 | |
|     if(it == itRoyalJelly) achievement_gain("JELLY1");
 | |
|     if(it == itWine) achievement_gain("WINE1");
 | |
|     if(it == itPower) achievement_gain("POWER1");
 | |
|     if(it == itEmerald) achievement_gain("EMERALD1");
 | |
|     if(it == itSilver) achievement_gain("SILVER1");
 | |
|     if(it == itGrimoire) achievement_gain("GRIMOIRE1");
 | |
|     if(it == itRedGem) achievement_gain("REDGEM1");
 | |
|     if(it == itPirate) achievement_gain("PIRATE1");
 | |
|     if(it == itCoast) achievement_gain("COAST1");
 | |
|     // if(it == itWhirlpool) achievement_gain("WHIRL1"); // requires escape
 | |
|     if(it == itBombEgg) achievement_gain("MINE1");
 | |
|     if(it == itPalace) achievement_gain("RUG1");
 | |
|     if(it == itFjord) achievement_gain("GARNET1");
 | |
| 
 | |
|     if(it == itIvory) achievement_gain("TOWER1");
 | |
|     if(it == itElemental) achievement_gain("ELEMENT1");
 | |
|     if(it == itZebra) achievement_gain("ZEBRA1");
 | |
| 
 | |
|     if(it == itMutant) achievement_gain("MUTANT1");
 | |
|     if(it == itFulgurite) achievement_gain("FULGUR1");
 | |
| 
 | |
|     if(it == itMutant2) achievement_gain("FRUIT1");
 | |
|     if(it == itWindstone) achievement_gain("DOVE1");
 | |
|     if(it == itCoral) achievement_gain("CORAL1");
 | |
|     if(it == itRose) achievement_gain("ROSE1");
 | |
|     
 | |
|     if(it == itBabyTortoise) achievement_gain("TORTOISE1");
 | |
|     if(it == itDragon) achievement_gain("DRAGON1");
 | |
|     if(it == itApple) achievement_gain("APPLE1");
 | |
| 
 | |
|     if(it == itKraken) achievement_gain("KRAKEN1");
 | |
|     if(it == itBarrow) achievement_gain("BARROW1");
 | |
|     if(it == itTrollEgg) achievement_gain("TROLL1");
 | |
| 
 | |
|     if(it == itAmethyst) achievement_gain("MOUNT1");
 | |
|     if(it == itSlime) achievement_gain("DUNG1");
 | |
|     if(it == itDodeca) achievement_gain("DOD1");
 | |
| 
 | |
|     if(it == itGreenGrass) achievement_gain("PRAIR1");
 | |
|     if(it == itBull) achievement_gain("BULL1");
 | |
|     
 | |
|     if(it == itHunting) achievement_gain("TURQ1");
 | |
|     if(it == itBlizzard) achievement_gain("BLIZZ1");
 | |
|     if(it == itLavaLily) achievement_gain("LILY1");
 | |
|     if(it == itTerra) achievement_gain("TERRAC1");
 | |
|     
 | |
|     if(it == itRuins) achievement_gain("RUIN1");
 | |
|     if(it == itSwitch) achievement_gain("JELLZ1");
 | |
|     
 | |
|     if(it == itBrownian) achievement_gain("BROWN1");
 | |
|     if(it == itVarTreasure) achievement_gain("RADIO1");
 | |
|     if(it == itWest) achievement_gain("FREEFALL1");
 | |
|     
 | |
|     if(it == itFrog) achievement_gain("FROG1");
 | |
|     if(it == itEclectic) achievement_gain("ECLEC1");
 | |
|     if(it == itWet) achievement_gain("WET1");
 | |
| 
 | |
|     if(it == itCursed) achievement_gain("CURSED1");
 | |
|     if(it == itDice) achievement_gain("DICE1");
 | |
|     }
 | |
| 
 | |
|   // 32
 | |
|   if(it == itHolyGrail) {
 | |
|     if(q == 1) achievement_gain("GRAIL2");
 | |
|     achievement_gain("GRAILH", specgeom_heptagonal());
 | |
|     #if CAP_CRYSTAL
 | |
|     achievement_gain("GRAIL4D", specgeom_crystal1());
 | |
|     achievement_gain("GRAIL4D2", specgeom_crystal2());
 | |
|     #endif
 | |
|     if(q == 3) achievement_gain("GRAIL3");
 | |
|     if(q == 8) achievement_gain("GRAIL4");
 | |
|     }
 | |
|   
 | |
|   if(q == (inv::on ? 25 : 10)) {
 | |
|     if(it == itDiamond) achievement_gain("DIAMOND2");
 | |
|     if(it == itRuby) achievement_gain("RUBY2");
 | |
|     if(it == itHyperstone) achievement_gain("HYPER2");
 | |
|     if(it == itGold) achievement_gain("GOLD2");
 | |
|     if(it == itStatue) achievement_gain("STATUE2");
 | |
|     if(it == itShard) achievement_gain("MIRROR2");
 | |
|     if(it == itBone) achievement_gain("TOTEM2");
 | |
|     if(it == itSpice) achievement_gain("SPICE2");
 | |
|     if(it == itElixir) achievement_gain("ELIXIR2");
 | |
|     if(it == itHell) achievement_gain("DAISY2");
 | |
|     if(it == itFeather) achievement_gain("FEATHER2");
 | |
|     if(it == itSapphire) achievement_gain("SAPPHIRE2");
 | |
|     if(it == itFernFlower) achievement_gain("FERN2");
 | |
|     if(it == itRoyalJelly) achievement_gain("JELLY2");
 | |
|     if(it == itWine) achievement_gain("WINE2");
 | |
|     if(it == itPower) achievement_gain("POWER2");
 | |
|     if(it == itEmerald) achievement_gain("EMERALD2");
 | |
|     if(it == itSilver) achievement_gain("SILVER2");
 | |
|     if(it == itGrimoire) achievement_gain("GRIMOIRE2");
 | |
|     if(it == itRedGem) achievement_gain("REDGEM2");
 | |
|     if(it == itPirate) achievement_gain("PIRATE2");
 | |
|     if(it == itCoast) achievement_gain("COAST2");
 | |
|     if(it == itWhirlpool) achievement_gain("WHIRL2");
 | |
|     if(it == itBombEgg) achievement_gain("MINE2");
 | |
|     if(it == itPalace) achievement_gain("RUG2");
 | |
|     if(it == itFjord) achievement_gain("GARNET2");
 | |
| 
 | |
|     if(it == itIvory) achievement_gain("TOWER2");
 | |
|     if(it == itElemental) achievement_gain("ELEMENT2");
 | |
|     if(it == itZebra) achievement_gain("ZEBRA2");
 | |
| 
 | |
|     if(it == itMutant) achievement_gain("MUTANT2");
 | |
|     if(it == itFulgurite) achievement_gain("FULGUR2");
 | |
| 
 | |
|     if(it == itMutant2) achievement_gain("FRUIT2");
 | |
|     if(it == itWindstone) achievement_gain("DOVE2");
 | |
|     if(it == itCoral) achievement_gain("CORAL2");
 | |
|     if(it == itRose) achievement_gain("ROSE2");
 | |
| 
 | |
|     if(it == itBabyTortoise) achievement_gain("TORTOISE2");
 | |
|     if(it == itDragon) achievement_gain("DRAGON2");
 | |
|     if(it == itApple) achievement_gain("APPLE2");
 | |
| 
 | |
|     if(it == itKraken) achievement_gain("KRAKEN2");
 | |
|     if(it == itBarrow) achievement_gain("BARROW2");
 | |
|     if(it == itTrollEgg) achievement_gain("TROLL2");
 | |
| 
 | |
|     if(it == itAmethyst) achievement_gain("MOUNT2");
 | |
|     if(it == itSlime) achievement_gain("DUNG2");
 | |
|     if(it == itDodeca) achievement_gain("DOD2");
 | |
| 
 | |
|     if(it == itGreenGrass) achievement_gain("PRAIR2");
 | |
|     if(it == itBull) achievement_gain("BULL2");
 | |
|     
 | |
|     if(it == itHunting) achievement_gain("TURQ2");
 | |
|     if(it == itBlizzard) achievement_gain("BLIZZ2");
 | |
|     if(it == itLavaLily) achievement_gain("LILY2");
 | |
|     if(it == itTerra) achievement_gain("TERRAC2");
 | |
| 
 | |
|     if(it == itRuins) achievement_gain("RUIN2");
 | |
|     if(it == itSwitch) achievement_gain("JELLZ2");
 | |
| 
 | |
|     if(it == itBrownian) achievement_gain("BROWN2");
 | |
|     if(it == itVarTreasure) achievement_gain("RADIO2");
 | |
|     if(it == itWest) achievement_gain("FREEFALL2");
 | |
|     
 | |
|     if(it == itFrog) achievement_gain("FROG2");
 | |
|     if(it == itEclectic) achievement_gain("ECLEC2");
 | |
|     if(it == itWet) achievement_gain("WET2");
 | |
| 
 | |
|     if(it == itCursed) achievement_gain("CURSED2");
 | |
|     if(it == itDice) achievement_gain("DICE2");
 | |
|     }
 | |
| 
 | |
|   if(q == (inv::on ? 50 : 25)) {
 | |
|     if(it == itDiamond) achievement_gain("DIAMOND3");
 | |
|     if(it == itRuby) achievement_gain("RUBY3");
 | |
|     if(it == itHyperstone) achievement_gain("HYPER3");
 | |
|     if(it == itGold) achievement_gain("GOLD3");
 | |
|     if(it == itStatue) achievement_gain("STATUE3");
 | |
|     if(it == itShard) achievement_gain("MIRROR3");
 | |
|     if(it == itBone) achievement_gain("TOTEM3");
 | |
|     if(it == itSpice) achievement_gain("SPICE3");
 | |
|     if(it == itElixir) achievement_gain("ELIXIR3");
 | |
|     if(it == itHell) achievement_gain("DAISY3");
 | |
|     if(it == itFeather) achievement_gain("FEATHER3");
 | |
|     if(it == itSapphire) achievement_gain("SAPPHIRE3");
 | |
|     if(it == itFernFlower) achievement_gain("FERN3");
 | |
|     if(it == itRoyalJelly) achievement_gain("JELLY3");
 | |
|     if(it == itWine) achievement_gain("WINE3");
 | |
|     if(it == itPower) achievement_gain("POWER3");
 | |
|     if(it == itEmerald) achievement_gain("EMERALD3");
 | |
|     if(it == itSilver) achievement_gain("SILVER3");
 | |
|     if(it == itGrimoire) achievement_gain("GRIMOIRE3");
 | |
|     if(it == itRedGem) achievement_gain("REDGEM3");
 | |
|     if(it == itPirate) achievement_gain("PIRATE3");
 | |
|     if(it == itCoast) achievement_gain("COAST3");
 | |
|     if(it == itWhirlpool) achievement_gain("WHIRL3");
 | |
|     if(it == itBombEgg) achievement_gain("MINE3");
 | |
|     if(it == itPalace) achievement_gain("RUG3");
 | |
|     if(it == itFjord) achievement_gain("GARNET3");
 | |
| 
 | |
|     if(it == itIvory) achievement_gain("TOWER3");
 | |
|     if(it == itElemental) achievement_gain("ELEMENT3");
 | |
|     if(it == itZebra) achievement_gain("ZEBRA3");
 | |
| 
 | |
|     if(it == itMutant) achievement_gain("MUTANT3");
 | |
|     if(it == itFulgurite) achievement_gain("FULGUR3");
 | |
|     
 | |
|     if(it == itMutant2) achievement_gain("FRUIT3");
 | |
|     if(it == itWindstone) achievement_gain("DOVE3");
 | |
|     if(it == itCoral) achievement_gain("CORAL3");
 | |
|     if(it == itRose) achievement_gain("ROSE3");
 | |
| 
 | |
|     if(it == itFulgurite && pureHardcore() && elec::lightningfast == 0)
 | |
|       achievement_gain("HARDMETAL");
 | |
| 
 | |
|     if(it == itBabyTortoise) achievement_gain("TORTOISE3");
 | |
|     if(it == itDragon) achievement_gain("DRAGON3");
 | |
|     if(it == itApple) achievement_gain("APPLE3");
 | |
| 
 | |
|     if(it == itKraken) achievement_gain("KRAKEN3");
 | |
|     if(it == itBarrow) achievement_gain("BARROW3");
 | |
|     if(it == itTrollEgg) achievement_gain("TROLL3");
 | |
| 
 | |
|     if(it == itAmethyst) achievement_gain("MOUNT3");
 | |
|     if(it == itSlime) achievement_gain("DUNG3");
 | |
|     if(it == itDodeca) achievement_gain("DOD3");
 | |
| 
 | |
|     if(it == itGreenGrass) achievement_gain("PRAIR3");
 | |
|     if(it == itBull) achievement_gain("BULL3");
 | |
|     
 | |
|     if(it == itHunting) achievement_gain("TURQ3");
 | |
|     if(it == itBlizzard) achievement_gain("BLIZZ3");
 | |
|     if(it == itLavaLily) achievement_gain("LILY3");
 | |
|     if(it == itTerra) achievement_gain("TERRAC3");
 | |
| 
 | |
|     if(it == itRuins) achievement_gain("RUIN3");
 | |
|     if(it == itSwitch) achievement_gain("JELLZ3");
 | |
| 
 | |
|     if(it == itBrownian) achievement_gain("BROWN3");
 | |
|     if(it == itVarTreasure) achievement_gain("RADIO3");
 | |
|     if(it == itWest) achievement_gain("FREEFALL3");
 | |
|     
 | |
|     if(it == itFrog) achievement_gain("FROG3");
 | |
|     if(it == itEclectic) achievement_gain("ECLEC3");
 | |
|     if(it == itWet) achievement_gain("WET3");
 | |
| 
 | |
|     if(it == itCursed) achievement_gain("CURSED3");
 | |
|     if(it == itDice) achievement_gain("DICE3");
 | |
|     }
 | |
| 
 | |
|   if(q == 50 && !inv::on) {
 | |
|     if(it == itDiamond) achievement_gain("DIAMOND4");
 | |
|     if(it == itRuby) achievement_gain("RUBY4");
 | |
|     if(it == itHyperstone) achievement_gain("HYPER4");
 | |
|     if(it == itGold) achievement_gain("GOLD4");
 | |
|     if(it == itStatue) achievement_gain("STATUE4");
 | |
|     if(it == itShard) achievement_gain("MIRROR4");
 | |
|     if(it == itBone) achievement_gain("TOTEM4");
 | |
|     if(it == itSpice) achievement_gain("SPICE4");
 | |
|     if(it == itElixir) achievement_gain("ELIXIR4");
 | |
|     if(it == itHell) achievement_gain("DAISY4");
 | |
|     if(it == itFeather) achievement_gain("FEATHER4");
 | |
|     if(it == itSapphire) achievement_gain("SAPPHIRE4");
 | |
|     if(it == itFernFlower) achievement_gain("FERN4");
 | |
|     if(it == itRoyalJelly) achievement_gain("JELLY4");
 | |
|     if(it == itWine) achievement_gain("WINE4");
 | |
|     if(it == itPower) achievement_gain("POWER4");
 | |
|     if(it == itEmerald) achievement_gain("EMERALD4");
 | |
|     if(it == itSilver) achievement_gain("SILVER4");
 | |
|     if(it == itGrimoire) achievement_gain("GRIMOIRE4");
 | |
|     if(it == itRedGem) achievement_gain("REDGEM4");
 | |
|     if(it == itPirate) achievement_gain("PIRATE4");
 | |
|     if(it == itCoast) achievement_gain("COAST4");
 | |
|     if(it == itWhirlpool) achievement_gain("WHIRL4");
 | |
|     if(it == itBombEgg) achievement_gain("MINE4");
 | |
|     if(it == itPalace) achievement_gain("RUG4");
 | |
|     if(it == itFjord) achievement_gain("GARNET4");
 | |
| 
 | |
|     if(it == itIvory) achievement_gain("TOWER4");
 | |
|     if(it == itElemental) achievement_gain("ELEMENT4");
 | |
|     if(it == itZebra) achievement_gain("ZEBRA4");
 | |
| 
 | |
|     if(it == itMutant) achievement_gain("MUTANT4");
 | |
|     if(it == itFulgurite) achievement_gain("FULGUR4");
 | |
| 
 | |
|     if(it == itMutant2) achievement_gain("FRUIT4");
 | |
|     if(it == itWindstone) achievement_gain("DOVE4");
 | |
|     if(it == itCoral) achievement_gain("CORAL4");
 | |
|     if(it == itRose) achievement_gain("ROSE4");
 | |
| 
 | |
|     if(it == itBabyTortoise) achievement_gain("TORTOISE4");
 | |
|     if(it == itDragon) achievement_gain("DRAGON4");
 | |
|     if(it == itApple) achievement_gain("APPLE4");
 | |
| 
 | |
|     if(it == itKraken) achievement_gain("KRAKEN4");
 | |
|     if(it == itBarrow) achievement_gain("BARROW4");
 | |
|     if(it == itTrollEgg) achievement_gain("TROLL4");
 | |
| 
 | |
|     if(it == itAmethyst) achievement_gain("MOUNT4");
 | |
|     if(it == itSlime) achievement_gain("DUNG4");
 | |
|     if(it == itDodeca) achievement_gain("DOD4");
 | |
| 
 | |
|     if(it == itGreenGrass) achievement_gain("PRAIR4");
 | |
|     if(it == itBull) achievement_gain("BULL4");
 | |
|     
 | |
|     if(it == itHunting) achievement_gain("TURQ4");
 | |
|     if(it == itBlizzard) achievement_gain("BLIZZ4");
 | |
|     if(it == itLavaLily) achievement_gain("LILY4");
 | |
|     if(it == itTerra) achievement_gain("TERRAC4");
 | |
| 
 | |
|     if(it == itRuins) achievement_gain("RUIN4");
 | |
|     if(it == itSwitch) achievement_gain("JELLZ4");
 | |
| 
 | |
|     if(it == itBrownian) achievement_gain("BROWN4");
 | |
|     if(it == itVarTreasure) achievement_gain("RADIO4");
 | |
|     if(it == itWest) achievement_gain("FREEFALL4");
 | |
|     
 | |
|     if(it == itFrog) achievement_gain("FROG4");
 | |
|     if(it == itEclectic) achievement_gain("ECLEC4");
 | |
|     if(it == itWet) achievement_gain("WET4");
 | |
| 
 | |
|     if(it == itCursed) achievement_gain("CURSED4");
 | |
|     if(it == itDice) achievement_gain("DICE4");
 | |
|     }
 | |
|   
 | |
|   if(it == itOrbYendor) {
 | |
|     achievement_gain("YENDOR2");
 | |
|     if(pureHardcore()) achievement_gain("HARDCORE");
 | |
|     if(shmup::on) achievement_gain("SHMUP", rg::shmup);
 | |
|     }
 | |
|   }
 | |
| 
 | |
| /** This function awards 'counting' achievements, such as kill 10 monsters at the same time.
 | |
|  *  @param s name of the group of achievements, e.g. GOLEM.
 | |
|  *  @param current our score, e.g., the the achievement GOLEM2 will be awared with current >= 5.
 | |
|  *  @param prev previous value of the score.
 | |
|  */
 | |
| 
 | |
| EX void achievement_count(const string& s, int current, int prev) {
 | |
|   if(cheater && !test_achievements) return;
 | |
|   if(casual && !test_achievements) return;
 | |
|   if(shmup::on) return;
 | |
|   if(randomPatternsMode) return;
 | |
|   LATE( achievement_count(s, current, prev); )
 | |
| 
 | |
|   if(s == "GOLEM" && current >= 5)
 | |
|     achievement_gain("GOLEM2");
 | |
|   if(s == "GOLEM" && current >= 10)
 | |
|     achievement_gain("GOLEM3");
 | |
|   if(s == "STAB" && current >= 1)
 | |
|     achievement_gain("STABBER1");
 | |
|   if(s == "STAB" && current >= 2)
 | |
|     achievement_gain("STABBER2");
 | |
|   if(s == "SLASH" && current >= 2)
 | |
|     achievement_gain("SLASH2");
 | |
|   if(s == "STAB" && current >= 4)
 | |
|     achievement_gain("STABBER3");
 | |
|   if(s == "MIRRORKILL" && current-prev >= 1)
 | |
|     achievement_gain("MIRRORKILL1");
 | |
|   if(s == "MIRRORKILL" && current-prev >= 2)
 | |
|     achievement_gain("MIRRORKILL2");
 | |
|   if(s == "MIRRORKILL" && current-prev >= 3)
 | |
|     achievement_gain("MIRRORKILL3");
 | |
|   if(s == "FLASH" && current-prev >= 1)
 | |
|     achievement_gain("FLASH1");
 | |
|   if(s == "FLASH" && current-prev >= 5)
 | |
|     achievement_gain("FLASH2");
 | |
|   if(s == "FLASH" && current-prev >= 10)
 | |
|     achievement_gain("FLASH3");
 | |
|   if(s == "LIGHTNING" && current-prev >= 1)
 | |
|     achievement_gain("LIGHTNING1");
 | |
|   if(s == "LIGHTNING" && current-prev >= 5)
 | |
|     achievement_gain("LIGHTNING2");
 | |
|   if(s == "LIGHTNING" && current-prev >= 10)
 | |
|     achievement_gain("LIGHTNING3");
 | |
|   if(s == "MIRAGE" && current >= 35)
 | |
|     achievement_gain("MIRAGE", specgeom_euclid_gen());
 | |
|   if(s == "ORB" && current >= 10)
 | |
|     achievement_gain("ORB3");
 | |
|   if(s == "BUG" && current >= 1000)
 | |
|     achievement_gain("BUG3");
 | |
|   if(s == "ELEC" && current >= 10)
 | |
|     achievement_gain("ELEC3");
 | |
|   if(s == "BOWVARIETY" && current >= 2)
 | |
|     achievement_gain("BOWVARIETY1");
 | |
|   if(s == "BOWVARIETY" && current >= 6)
 | |
|     achievement_gain("BOWVARIETY2");
 | |
|   }
 | |
| 
 | |
| int specific_improved = 0;
 | |
| int specific_what = 0;
 | |
| 
 | |
| EX void improve_score(int i, eItem what) {
 | |
|   if(offlineMode) return;
 | |
|   LATE( improve_score(i, what); )
 | |
| #if CAP_ACHIEVE
 | |
|   if(haveLeaderboard(i)) updateHi(what, get_currentscore(i));
 | |
|   if(items[what] && haveLeaderboard(i)) {
 | |
|     if(items[what] > get_currentscore(i) && score_loaded(i)) {
 | |
|       specific_improved++; specific_what = what;
 | |
|       }
 | |
|     upload_score(i, items[what]);
 | |
|     }
 | |
| #endif
 | |
|   }
 | |
| 
 | |
| // scores for special challenges
 | |
| EX void achievement_score(int cat, int number) {
 | |
|   if(offlineMode) return;
 | |
| #if CAP_ACHIEVE
 | |
|   if(cheater) return;
 | |
|   if(casual) return;
 | |
|   LATE( achievement_score(cat, number); )
 | |
|   if(disksize) return;
 | |
|   if(cat == LB_HALLOWEEN) {
 | |
|     if(geometry != gSphere && geometry != gElliptic)
 | |
|       return;
 | |
|     }
 | |
|   else {
 | |
|     if(geometry) return;
 | |
|     if(ineligible_starting_land) return;
 | |
|     }
 | |
|   if(CHANGED_VARIATION) return;
 | |
|   if(randomPatternsMode) return;
 | |
|   if(dual::state) return;
 | |
|   if(shmup::on && cat != LB_PURE_TACTICS_SHMUP && cat != LB_PURE_TACTICS_COOP && cat != LB_RACING) return;
 | |
|   if(yendor::on && cat != LB_YENDOR_CHALLENGE) return;
 | |
|   if(tactic::on && cat != LB_PURE_TACTICS && cat != LB_PURE_TACTICS_SHMUP && cat != LB_PURE_TACTICS_COOP) 
 | |
|     return;
 | |
|   if(racing::on && cat != LB_RACING) return;
 | |
|   if(bow::weapon) return;
 | |
|   if(use_custom_land_list) return;
 | |
|   upload_score(cat, number);
 | |
| #endif
 | |
|   }
 | |
| 
 | |
| EX void improveItemScores() {
 | |
|   LATE( improveItemScores(); )
 | |
|   for(int i=1; i<=12; i++) improve_score(i, eItem(i));
 | |
|   improve_score(17, itOrbYendor);
 | |
|   improve_score(18, itFernFlower);
 | |
|   improve_score(19, itRoyalJelly);
 | |
|   improve_score(20, itPower);
 | |
|   improve_score(21, itSilver);
 | |
|   improve_score(22, itWine);
 | |
|   improve_score(23, itEmerald);
 | |
|   improve_score(24, itGrimoire);
 | |
|   improve_score(25, itHolyGrail);
 | |
|   improve_score(26, itRedGem);
 | |
|   improve_score(27, itPirate);
 | |
|   improve_score(31, itBombEgg);
 | |
|   improve_score(32, itCoast);
 | |
|   improve_score(33, itWhirlpool);
 | |
|   improve_score(34, itPalace);
 | |
|   improve_score(35, itFjord);
 | |
|   
 | |
|   improve_score(37, itIvory);
 | |
|   improve_score(38, itElemental);
 | |
|   improve_score(39, itZebra);
 | |
| 
 | |
|   improve_score(42, itMutant);
 | |
|   improve_score(43, itFulgurite);
 | |
| 
 | |
|   if(!isHaunted(cwt.at->land)) improve_score(46, itLotus);
 | |
|   improve_score(47, itMutant2);
 | |
|   improve_score(48, itWindstone);
 | |
|   
 | |
|   improve_score(51, itCoral);
 | |
|   improve_score(52, itRose);
 | |
| 
 | |
|   improve_score(54, itBabyTortoise);
 | |
|   improve_score(55, itDragon);
 | |
|   improve_score(56, itApple);
 | |
| 
 | |
|   improve_score(58, itKraken);
 | |
|   improve_score(59, itBarrow);
 | |
|   improve_score(60, itTrollEgg);
 | |
|   
 | |
|   improve_score(64, itAmethyst);
 | |
|   improve_score(65, itSlime);
 | |
|   improve_score(66, itDodeca);
 | |
| 
 | |
|   improve_score(67, itGreenGrass);
 | |
|   improve_score(68, itBull);
 | |
| 
 | |
|   improve_score(72, itTerra);
 | |
|   improve_score(73, itBlizzard);
 | |
|   improve_score(74, itLavaLily);
 | |
|   improve_score(75, itHunting);
 | |
|   
 | |
|   improve_score(76, itRuins);
 | |
|   improve_score(77, itSwitch);
 | |
|   
 | |
|   improve_score(78, itBrownian);
 | |
|   improve_score(79, itVarTreasure);
 | |
|   improve_score(80, itWest);
 | |
|   
 | |
|   improve_score(82, itFrog);
 | |
|   improve_score(83, itEclectic);
 | |
|   improve_score(84, itWet);
 | |
| 
 | |
|   improve_score(85, itCursed);
 | |
|   improve_score(86, itDice);
 | |
|   }
 | |
| 
 | |
| int next_stat_tick;
 | |
| 
 | |
| /** gain the final achievements. 
 | |
|  *  @param really false: the user is simply looking at the score; true: the game really ended.
 | |
|  */
 | |
| EX void achievement_final(bool really_final) {
 | |
|   if(offlineMode) return;
 | |
| 
 | |
|   LATE( achievement_final(really_final); )
 | |
| 
 | |
| #if CAP_ACHIEVE
 | |
|   if(ticks > next_stat_tick) {
 | |
|     upload_score(LB_STATISTICS, time(NULL));
 | |
|     next_stat_tick = ticks + 600000;
 | |
|     }
 | |
|   if(cheater) return;
 | |
|   if(casual) return;
 | |
| 
 | |
| #if CAP_TOUR
 | |
|   if(tour::on) return;
 | |
| #endif
 | |
|   
 | |
|   if(randomPatternsMode) return;
 | |
|   if(peace::on) return;
 | |
|   if(yendor::on) return;
 | |
|   if(dual::state) return;
 | |
| 
 | |
|   if(tactic::on) {
 | |
|     tactic::record();
 | |
|     tactic::unrecord();
 | |
|     tactic::uploadScore();
 | |
|     return;
 | |
|     }
 | |
| 
 | |
| #if CAP_DAILY
 | |
|   if(daily::on) {
 | |
|     daily::uploadscore(really_final);
 | |
|     return;
 | |
|     }  
 | |
| #endif
 | |
|   
 | |
|   int specialcode = 0;
 | |
|   if(shmup::on) specialcode++;
 | |
|   if(ls::std_chaos()) specialcode+=2;
 | |
|   else if(!ls::nice_walls()) return;
 | |
|   if(PURE) specialcode+=4;
 | |
|   if(numplayers() > 1) specialcode+=8;
 | |
|   if(inv::on) specialcode+=16;
 | |
|   if(bow::crossbow_mode() && bow::style == bow::cbBull) specialcode += 32;
 | |
|   if(bow::crossbow_mode() && bow::style == bow::cbGeodesic) specialcode += 64;
 | |
|   if(bow::crossbow_mode() && bow::style == bow::cbGeometric) specialcode += 96;
 | |
|   if(shmup::on && vid.creature_scale != 1) return;
 | |
|   
 | |
|   if(sphere && specialland == laHalloween) {
 | |
|     if(specialcode) return;
 | |
|     achievement_score(LB_HALLOWEEN, items[itTreat]);
 | |
|     return;
 | |
|     }
 | |
| 
 | |
|   if(ineligible_starting_land) return;
 | |
|   if(geometry) return;
 | |
|   if(NONSTDVAR) return;
 | |
|   if(use_custom_land_list) return;
 | |
| 
 | |
|   if(numplayers() > 1 && !multi::friendly_fire) return;
 | |
|   if(numplayers() > 1 && multi::pvp_mode) return;
 | |
|   if(numplayers() > 1 && multi::split_screen) return;
 | |
|   
 | |
|   // determine the correct leaderboard ID for 'total score'
 | |
|   // or return if no leaderboard for the current mode
 | |
|   int sid;
 | |
|   switch(specialcode) {
 | |
|     case 0:  sid = 0; break;
 | |
|     case 1:  sid = 28; break;
 | |
|     case 2:  sid = 53; break;
 | |
|     case 4:  sid = 57; break;
 | |
|     case 8:  sid = 61; break;
 | |
|     case 9:  sid = 44; break;
 | |
|     case 16: sid = 69; break;
 | |
|     case 32: sid = 87; break;
 | |
|     case 64: sid = 88; break;
 | |
|     case 96: sid = 89; break;
 | |
|     default: return;
 | |
|     }
 | |
|       
 | |
|   int total_improved = 0;
 | |
|   specific_improved = 0;
 | |
|   specific_what = 0;
 | |
|   
 | |
|   if(specialcode == 0) improveItemScores(); 
 | |
|   
 | |
|   int tg = gold();
 | |
|   if(tg && haveLeaderboard(sid)) {
 | |
|     if(tg > get_currentscore(sid) && score_loaded(sid)) {
 | |
|       if(get_currentscore(sid) <= 0) total_improved += 2;
 | |
|       total_improved++; // currentscore[sid] = tg;
 | |
|       }
 | |
|     upload_score(sid, tg);
 | |
|     }
 | |
| 
 | |
|   if(total_improved >= 2) {
 | |
| #if !ISANDROID  
 | |
|     addMessage(XLAT("Your total treasure has been recorded in the " LEADERFULL "."));
 | |
|     addMessage(XLAT("Congratulations!"));
 | |
| #endif
 | |
|     }
 | |
|   else if(total_improved && specific_improved >= 2)
 | |
|     addMessage(XLAT("You have improved your total high score and %1 specific high scores!", its(specific_improved)));
 | |
|   else if(total_improved && specific_improved)
 | |
|     addMessage(XLAT("You have improved your total and '%1' high score!", iinf[specific_what].name));
 | |
|   else if(total_improved) {
 | |
| #if !ISANDROID  
 | |
|     addMessage(XLAT("You have improved your total high score on " LEADER ". Congratulations!"));
 | |
| #endif
 | |
|     }
 | |
|   else if(specific_improved >= 2)
 | |
|     addMessage(XLAT("You have improved %1 of your specific high scores!", its(specific_improved)));
 | |
|   else if(specific_improved) {
 | |
| #if !ISANDROID  
 | |
|     addMessage(XLAT("You have improved your '%1' high score on " LEADER "!", iinf[specific_what].name));
 | |
| #endif
 | |
|     }
 | |
| #endif
 | |
|   }
 | |
| 
 | |
| EX bool hadtotalvictory;
 | |
| 
 | |
| EX void check_total_victory() {
 | |
|   if(!inv::on) return;
 | |
|   if(hadtotalvictory) return;
 | |
|   if(!items[itOrbYendor]) return;
 | |
|   if(!items[itHolyGrail]) return;
 | |
|   if(items[itHyperstone] < 50) return;
 | |
|   if(!princess::reviveAt) return;
 | |
|   LATE( check_total_victory(); )
 | |
|   hadtotalvictory = true;
 | |
|   achievement_gain("TOTALVICTORY");
 | |
|   }
 | |
|   
 | |
| /** gain the victory achievements. 
 | |
|  *  @param hyper true for the Hyperstone victory, and false for the Orb of Yendor victory.
 | |
|  */
 | |
| EX void achievement_victory(bool hyper) {
 | |
|   DEBBI(DF_STEAM, ("achievement_victory"))
 | |
|   if(offlineMode) return;
 | |
| #if CAP_ACHIEVE
 | |
|   if(cheater) return;
 | |
|   if(casual) return;
 | |
|   if(bow::weapon) return;
 | |
|   if(geometry) return;
 | |
|   if(CHANGED_VARIATION) return;
 | |
|   if(randomPatternsMode) return;
 | |
|   if(hyper && shmup::on) return;
 | |
|   if(yendor::on) return;
 | |
|   if(peace::on) return;
 | |
|   if(tactic::on) return;
 | |
|   if(!ls::nice_walls()) return;
 | |
|   if(ineligible_starting_land) return;
 | |
|   if(use_custom_land_list) return;
 | |
|   LATE( achievement_victory(hyper); )
 | |
|   DEBB(DF_STEAM, ("after checks"))
 | |
| 
 | |
|   int t = getgametime();
 | |
|   
 | |
|   if(hyper && shmup::on) return;
 | |
|   if(hyper && inv::on) return;
 | |
|   
 | |
|   int ih1 = hyper ? 15 : inv::on ? 70 : shmup::on ? (numplayers() > 1 ? 45 : 29) : 13;
 | |
|   int ih2 = hyper ? 16 : inv::on ? 71 : shmup::on ? 30 : 14;
 | |
|   
 | |
|   int improved = 0;
 | |
|   if(score_loaded(ih1) && score_loaded(ih2)) {
 | |
|     if(get_currentscore(ih1) == score_default(ih1) || get_currentscore(ih2) == score_default(ih2))
 | |
|       improved += 4;
 | |
|     
 | |
|     if(get_currentscore(ih1) > t) {
 | |
|       improved++;
 | |
|       }
 | |
|   
 | |
|     if(get_currentscore(ih2) > turncount) {
 | |
|       improved+=2;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|   if(hyper)
 | |
|     addMessage(XLAT("You have collected 10 treasures of each type."));
 | |
| 
 | |
|   if(improved) {
 | |
|     if(improved >= 4) {
 | |
|       if(!hyper) addMessage(XLAT("This is your first victory!"));
 | |
| #if !ISANDROID
 | |
|       addMessage(XLAT("This has been recorded in the " LEADERFULL "."));
 | |
| #endif
 | |
|       addMessage(XLAT("The faster you get here, the better you are!"));
 | |
|       }
 | |
|     else if(improved >= 3) {
 | |
|       if(shmup::on)
 | |
|         addMessage(XLAT("You have improved both your real time and knife count. Congratulations!"));
 | |
|       else 
 | |
|         addMessage(XLAT("You have improved both your real time and turn count. Congratulations!"));
 | |
|       }
 | |
|     else if(improved == 1)
 | |
|       addMessage(XLAT("You have used less real time than ever before. Congratulations!"));
 | |
|     else if(improved == 2) {
 | |
|       if(shmup::on)
 | |
|         addMessage(XLAT("You have used less knives than ever before. Congratulations!"));
 | |
|       else
 | |
|         addMessage(XLAT("You have used less turns than ever before. Congratulations!"));
 | |
|       }
 | |
|     }
 | |
|   
 | |
|   DEBB(DF_STEAM, ("uploading scores"))
 | |
|   upload_score(ih1, t);
 | |
|   upload_score(ih2, turncount);
 | |
| #endif
 | |
|   }
 | |
| 
 | |
| /** call the achievement callbacks */
 | |
| EX void achievement_pump();
 | |
| 
 | |
| EX string get_rich_presence_text() {
 | |
| 
 | |
|   #if CAP_DAILY
 | |
|   if(daily::on)
 | |
|     return "Strange Challenge #" + its(daily::daily_id) + ", score " + its(gold());
 | |
|   #endif
 | |
|   
 | |
|   if(tour::on)
 | |
|     return "Guided Tour";
 | |
| 
 | |
|   string res;
 | |
|   if(geometry != gNormal || !BITRUNCATED || disksize)
 | |
|     res = res + full_geometry_name() + " ";
 | |
|   
 | |
|   if(land_structure != default_land_structure()) res += land_structure_name(false) + " ";
 | |
|   if(shmup::on) res += "shmup ";
 | |
|   if(dual::state) res += "dual ";
 | |
|   if(randomPatternsMode) res += "random ";
 | |
|   if(inv::on) res += "OSM ";
 | |
|   if(multi::players > 1) res += "multi ";
 | |
|   if(casual) res += "casual ";
 | |
|   if(bow::weapon) res += bow::style == bow::cbBull ? "bow/bull " : "bow/geo ";
 | |
| 
 | |
|   if(cheater || among(cwt.at->land, laCanvas, laCA)) 
 | |
|     return res + "(?)";
 | |
|   
 | |
|   if(yendor::on) {
 | |
|     res += "Yendor Challenge: " + yendor::name(yendor::challenge);
 | |
|     if(items[itOrbYendor]) res += " (level " + its(items[itOrbYendor]) + ")";
 | |
|     return res;
 | |
|     }
 | |
|   
 | |
|   if(peace::on) return res + "peaceful";
 | |
| 
 | |
|   if(tactic::on)
 | |
|     return res + "PTM: " + linf[specialland].name + " $" + its(gold());
 | |
| 
 | |
|   if(princess::challenge) return res + "Princess Challenge";
 | |
| 
 | |
|   #if CAP_RACING
 | |
|   if(racing::on) {
 | |
|     using namespace racing;
 | |
|     res = res + "racing in " + linf[specialland].name;
 | |
|     
 | |
|     for(int i=0; i<multi::players; i++) {
 | |
|       if(race_finish_tick[i]) 
 | |
|         res += racetimeformat(race_finish_tick[i] - race_start_tick);
 | |
|       }
 | |
|     
 | |
|     return res;
 | |
|     }
 | |
|   #endif
 | |
|   
 | |
|   res += linf[cwt.at->land].name;
 | |
|   res += ", " + its(gold()) + " $$$";
 | |
|   
 | |
|   return res;
 | |
|   }
 | |
| 
 | |
| /** display the last achievement gained. */
 | |
| EX void achievement_display() {
 | |
|   #if CAP_ACHIEVE
 | |
|   if(achievementTimer) {
 | |
|     int col = (ticks - achievementTimer);
 | |
|     if(col > 5000) { achievementTimer = 0; return; }
 | |
|     if(col > 2500) col = 5000 - col;
 | |
|     col /= 10; col *= 0x10101;
 | |
|     displayfr(vid.xres/2, vid.yres/4, 2, vid.fsize * 2, achievementMessage[0], col & 0xFFFF00, 8);
 | |
|     int w = 2 * vid.fsize;
 | |
| #if !ISMOBILE
 | |
|     while(w>3 && textwidth(w, achievementMessage[1]) > vid.xres) w--;
 | |
| #endif
 | |
|     displayfr(vid.xres/2, vid.yres/4 + vid.fsize*2, 2, w, achievementMessage[1], col, 8);
 | |
|     w = vid.fsize;
 | |
| #if !ISMOBILE
 | |
|     while(w>3 && textwidth(w, achievementMessage[2]) > vid.xres) w--;
 | |
| #endif
 | |
|     displayfr(vid.xres/2, vid.yres/4 + vid.fsize*4, 2, w, achievementMessage[2], col, 8);
 | |
|     }
 | |
|   #endif
 | |
|   }
 | |
| 
 | |
| EX bool isAscending(int i) { 
 | |
|   return i == 13 || i == 14 || i == 15 || i == 16 || i == 29 || i == 30 || i == 45;
 | |
|   }
 | |
| 
 | |
| EX int score_default(int i) {
 | |
|   if(isAscending(i)) return 1999999999;
 | |
|   else return 0;
 | |
|   }
 | |
| 
 | |
| }
 | 
