1 /*-------------------------------------------------------------------------------
2 
3 	BARONY
4 	File: scores.hpp
5 	Desc: header file for scores.cpp
6 
7 	Copyright 2013-2016 (c) Turning Wheel LLC, all rights reserved.
8 	See LICENSE for details.
9 
10 -------------------------------------------------------------------------------*/
11 
12 #pragma once
13 #include "monster.hpp"
14 
15 #define SCORESFILE "scores.dat"
16 #define SCORESFILE_MULTIPLAYER "scores_multiplayer.dat"
17 
18 // game score structure
19 #define MAXTOPSCORES 30
20 #define NUM_CONDUCT_CHALLENGES 32
21 #define NUM_GAMEPLAY_STATISTICS 64
22 
23 // indexes for new game conducts
24 static const int CONDUCT_HARDCORE = 0; // 2 state, 1 = hardcore, 0 = not.
25 static const int CONDUCT_CHEATS_ENABLED = 1; // 2 state, 1 = cheats enabled, 0 = not.
26 static const int CONDUCT_MULTIPLAYER = 2; // 2 state, 1 = multiplayer, 0 = not.
27 static const int CONDUCT_CLASSIC_MODE = 3; // 2 state, 1 = classic maps, 0 = not.
28 static const int CONDUCT_MODDED = 4; // 2 state, 1 = modded, 0 = not.
29 static const int CONDUCT_BRAWLER = 5; // 2 state, 1 = brawler, no weapons used, 0 = not brawler, weapons used.
30 static const int CONDUCT_BLESSED_BOOTS_SPEED = 6; // 2 state, 1 = reached Sanctum in < 45 mins, 0 = not.
31 static const int CONDUCT_BOOTS_SPEED = 7; // 2 state, 1 = beat Herx/Baphy in < 20 mins, 0 = not.
32 static const int CONDUCT_KEEPINVENTORY = 8; // 1 = keep inventory server flag, 0 = not.
33 static const int CONDUCT_LIFESAVING = 9; // 1 = lifesaving server flag, 0 = not.
34 static const int CONDUCT_ACCURSED = 10; // 1 = cursed, 0 = not
35 static const int CONDUCT_RANGED_ONLY = 11; // 1 = ranged only, 0 = not.
36 
37 static const int STATISTICS_BOMB_SQUAD = 0;
38 static const int STATISTICS_SITTING_DUCK = 1;
39 static const int STATISTICS_YES_WE_CAN = 2;
40 static const int STATISTICS_FIRE_MAYBE_DIFFERENT = 3;
41 static const int STATISTICS_HOT_TUB_TIME_MACHINE = 4;
42 static const int STATISTICS_HEAL_BOT = 5;
43 static const int STATISTICS_TEMPT_FATE = 6;
44 static const int STATISTICS_ALCHEMY_RECIPES = 7;
45 static const int STATISTICS_FUNCTIONAL = 8;
46 static const int STATISTICS_OHAI_MARK = 9;
47 static const int STATISTICS_ITS_A_LIVING = 10;
48 static const int STATISTICS_FORUM_TROLL = 11;
49 static const int STATISTICS_PIMPING_AINT_EASY = 12;
50 static const int STATISTICS_TRIBE_SUBSCRIBE = 13;
51 static const int STATISTICS_POP_QUIZ_1 = 14;
52 static const int STATISTICS_POP_QUIZ_2 = 15;
53 static const int STATISTICS_DISABLE_UPLOAD = 31;
54 
55 enum SteamStatIndexes : int
56 {
57 	STEAM_STAT_BOULDER_DEATHS,
58 	STEAM_STAT_RHINESTONE_COWBOY,
59 	STEAM_STAT_TOUGH_AS_NAILS,
60 	STEAM_STAT_UNSTOPPABLE_FORCE,
61 	STEAM_STAT_GAMES_STARTED,
62 	STEAM_STAT_GAMES_WON,
63 	STEAM_STAT_BOMBARDIER,
64 	STEAM_STAT_IN_THE_MIX,
65 	STEAM_STAT_FREE_REFILLS,
66 	STEAM_STAT_TAKE_THIS_OUTSIDE,
67 	STEAM_STAT_ALTER_EGO,
68 	STEAM_STAT_BLOOD_SPORT,
69 	STEAM_STAT_BAD_BLOOD,
70 	STEAM_STAT_IRON_GUT,
71 	STEAM_STAT_BOTTLE_NOSED,
72 	STEAM_STAT_BARFIGHT_CHAMP,
73 	STEAM_STAT_VOLATILE,
74 	STEAM_STAT_SURROGATES,
75 	STEAM_STAT_KILL_COMMAND,
76 	STEAM_STAT_TRASH_COMPACTOR,
77 	STEAM_STAT_SPICY,
78 	STEAM_STAT_SERIAL_THRILLA,
79 	STEAM_STAT_TRADITION,
80 	STEAM_STAT_POP_QUIZ,
81 	STEAM_STAT_DYSLEXIA,
82 	STEAM_STAT_BOOKWORM,
83 	STEAM_STAT_MONARCH,
84 	STEAM_STAT_SUPER_SHREDDER,
85 	STEAM_STAT_FIXER_UPPER,
86 	STEAM_STAT_TORCHERER,
87 	STEAM_STAT_MANY_PEDI_PALP,
88 	STEAM_STAT_5000_SECOND_RULE,
89 	STEAM_STAT_SOCIAL_BUTTERFLY,
90 	STEAM_STAT_ROLL_THE_BONES,
91 	STEAM_STAT_COWBOY_FROM_HELL,
92 	STEAM_STAT_SELF_FLAGELLATION,
93 	STEAM_STAT_CHOPPING_BLOCK,
94 	STEAM_STAT_IF_YOU_LOVE_SOMETHING,
95 	STEAM_STAT_RAGE_AGAINST,
96 	STEAM_STAT_GUERILLA_RADIO,
97 	STEAM_STAT_FASCIST,
98 	STEAM_STAT_ITS_A_LIVING,
99 	STEAM_STAT_OVERCLOCKED,
100 	STEAM_STAT_BACK_TO_BASICS,
101 	STEAM_STAT_EXTRA_CREDIT,
102 	STEAM_STAT_EXTRA_CREDIT_LVLS,
103 	STEAM_STAT_DIPLOMA,
104 	STEAM_STAT_DIPLOMA_LVLS,
105 	STEAM_STAT_TUTORIAL_ENTERED
106 };
107 
108 enum SteamGlobalStatIndexes : int
109 {
110 	STEAM_GSTAT_INVALID = -1,
111 	STEAM_GSTAT_GAMES_STARTED = 0,
112 	STEAM_GSTAT_GAMES_WON,
113 	STEAM_GSTAT_BOULDER_DEATHS,
114 	STEAM_GSTAT_HERX_SLAIN,
115 	STEAM_GSTAT_BAPHOMET_SLAIN,
116 	STEAM_GSTAT_TWINSFIRE_SLAIN,
117 	STEAM_GSTAT_DEATHS_HUMAN,
118 	STEAM_GSTAT_DEATHS_RAT,
119 	STEAM_GSTAT_DEATHS_GOBLIN,
120 	STEAM_GSTAT_DEATHS_SLIME,
121 	STEAM_GSTAT_DEATHS_TROLL,
122 	STEAM_GSTAT_DEATHS_SPIDER,
123 	STEAM_GSTAT_DEATHS_GHOUL,
124 	STEAM_GSTAT_DEATHS_SKELETON,
125 	STEAM_GSTAT_DEATHS_SCORPION,
126 	STEAM_GSTAT_DEATHS_IMP,
127 	STEAM_GSTAT_DEATHS_GNOME,
128 	STEAM_GSTAT_DEATHS_DEMON,
129 	STEAM_GSTAT_DEATHS_SUCCUBUS,
130 	STEAM_GSTAT_DEATHS_LICH,
131 	STEAM_GSTAT_DEATHS_MINOTAUR,
132 	STEAM_GSTAT_DEATHS_DEVIL,
133 	STEAM_GSTAT_DEATHS_SHOPKEEPER,
134 	STEAM_GSTAT_DEATHS_KOBOLD,
135 	STEAM_GSTAT_DEATHS_SCARAB,
136 	STEAM_GSTAT_DEATHS_CRYSTALGOLEM,
137 	STEAM_GSTAT_DEATHS_INCUBUS,
138 	STEAM_GSTAT_DEATHS_VAMPIRE,
139 	STEAM_GSTAT_DEATHS_SHADOW,
140 	STEAM_GSTAT_DEATHS_COCKATRICE,
141 	STEAM_GSTAT_DEATHS_INSECTOID,
142 	STEAM_GSTAT_DEATHS_GOATMAN,
143 	STEAM_GSTAT_DEATHS_AUTOMATON,
144 	STEAM_GSTAT_DEATHS_LICHICE,
145 	STEAM_GSTAT_DEATHS_LICHFIRE,
146 	STEAM_GSTAT_DEATHS_SENTRYBOT,
147 	STEAM_GSTAT_DEATHS_SPELLBOT,
148 	STEAM_GSTAT_DEATHS_GYROBOT,
149 	STEAM_GSTAT_DEATHS_DUMMYBOT,
150 	STEAM_GSTAT_TWINSICE_SLAIN,
151 	STEAM_GSTAT_SHOPKEEPERS_SLAIN,
152 	STEAM_GSTAT_MINOTAURS_SLAIN,
153 	STEAM_GSTAT_TUTORIAL_ENTERED,
154 	STEAM_GSTAT_TUTORIAL1_COMPLETED,
155 	STEAM_GSTAT_TUTORIAL2_COMPLETED,
156 	STEAM_GSTAT_TUTORIAL3_COMPLETED,
157 	STEAM_GSTAT_TUTORIAL4_COMPLETED,
158 	STEAM_GSTAT_TUTORIAL5_COMPLETED,
159 	STEAM_GSTAT_TUTORIAL6_COMPLETED,
160 	STEAM_GSTAT_TUTORIAL7_COMPLETED,
161 	STEAM_GSTAT_TUTORIAL8_COMPLETED,
162 	STEAM_GSTAT_TUTORIAL9_COMPLETED,
163 	STEAM_GSTAT_TUTORIAL10_COMPLETED,
164 	STEAM_GSTAT_TUTORIAL1_ATTEMPTS,
165 	STEAM_GSTAT_TUTORIAL2_ATTEMPTS,
166 	STEAM_GSTAT_TUTORIAL3_ATTEMPTS,
167 	STEAM_GSTAT_TUTORIAL4_ATTEMPTS,
168 	STEAM_GSTAT_TUTORIAL5_ATTEMPTS,
169 	STEAM_GSTAT_TUTORIAL6_ATTEMPTS,
170 	STEAM_GSTAT_TUTORIAL7_ATTEMPTS,
171 	STEAM_GSTAT_TUTORIAL8_ATTEMPTS,
172 	STEAM_GSTAT_TUTORIAL9_ATTEMPTS,
173 	STEAM_GSTAT_TUTORIAL10_ATTEMPTS,
174 	STEAM_GSTAT_DISABLE,
175 	STEAM_GSTAT_PROMO,
176 	STEAM_GSTAT_PROMO_INTERACT
177 };
178 
179 SteamGlobalStatIndexes getIndexForDeathType(int type);
180 
181 static const std::pair<std::string, int> steamStatAchStringsAndMaxVals[] =
182 {
183 	std::make_pair("BARONY_ACH_NONE", 999999),				// STEAM_STAT_BOULDER_DEATHS,
184 	std::make_pair("BARONY_ACH_RHINESTONE_COWBOY", 50),		// STEAM_STAT_RHINESTONE_COWBOY,
185 	std::make_pair("BARONY_ACH_TOUGH_AS_NAILS", 50),		// STEAM_STAT_TOUGH_AS_NAILS,
186 	std::make_pair("BARONY_ACH_UNSTOPPABLE_FORCE",50),		// STEAM_STAT_UNSTOPPABLE_FORCE,
187 	std::make_pair("BARONY_ACH_NONE", 999999),				// STEAM_STAT_GAMES_STARTED,
188 	std::make_pair("BARONY_ACH_NONE", 999999),				// STEAM_STAT_GAMES_WON,
189 	std::make_pair("BARONY_ACH_BOMBARDIER", 50),			// STEAM_STAT_BOMBARDIER,
190 	std::make_pair("BARONY_ACH_IN_THE_MIX", 50),			// STEAM_STAT_IN_THE_MIX,
191 	std::make_pair("BARONY_ACH_FREE_REFILLS", 50),			// STEAM_STAT_FREE_REFILLS,
192 	std::make_pair("BARONY_ACH_TAKE_THIS_OUTSIDE", 10),		// STEAM_STAT_TAKE_THIS_OUTSIDE,
193 	std::make_pair("BARONY_ACH_RICH_ALTER_EGO", 50000),		// STEAM_STAT_ALTER_EGO,
194 	std::make_pair("BARONY_ACH_BLOOD_SPORT", 50),			// STEAM_STAT_BLOOD_SPORT,
195 	std::make_pair("BARONY_ACH_BAD_BLOOD", 500),			// STEAM_STAT_BAD_BLOOD,
196 	std::make_pair("BARONY_ACH_IRON_GUT", 20),				// STEAM_STAT_IRON_GUT,
197 	std::make_pair("BARONY_ACH_BOTTLE_NOSED", 20),			// STEAM_STAT_BOTTLE_NOSED,
198 	std::make_pair("BARONY_ACH_BARFIGHT_CHAMP", 50),		// STEAM_STAT_BARFIGHT_CHAMP,
199 	std::make_pair("BARONY_ACH_VOLATILE", 20),				// STEAM_STAT_VOLATILE,
200 	std::make_pair("BARONY_ACH_SURROGATES", 50),			// STEAM_STAT_SURROGATES,
201 	std::make_pair("BARONY_ACH_KILL_COMMAND", 50),			// STEAM_STAT_KILL_COMMAND
202 	std::make_pair("BARONY_ACH_TRASH_COMPACTOR", 100),      // STEAM_STAT_TRASH_COMPACTOR
203 	std::make_pair("BARONY_ACH_SPICY", 10),                 // STEAM_STAT_SPICY
204 	std::make_pair("BARONY_ACH_SERIAL_THRILLA", 100),       // STEAM_STAT_SERIAL_THRILLA
205 	std::make_pair("BARONY_ACH_TRADITION", 20),             // STEAM_STAT_TRADITION
206 	std::make_pair("BARONY_ACH_POP_QUIZ", 20),              // STEAM_STAT_POP_QUIZ
207 	std::make_pair("BARONY_ACH_DYSLEXIA", 50),              // STEAM_STAT_DYSLEXIA
208 	std::make_pair("BARONY_ACH_BOOKWORM", 50),              // STEAM_STAT_BOOKWORM
209 	std::make_pair("BARONY_ACH_MONARCH", 20),               // STEAM_STAT_MONARCH
210 	std::make_pair("BARONY_ACH_SUPER_SHREDDER", 1000),      // STEAM_STAT_SUPER_SHREDDER
211 	std::make_pair("BARONY_ACH_FIXER_UPPER", 100),          // STEAM_STAT_FIXER_UPPER
212 	std::make_pair("BARONY_ACH_TORCHERER", 100),            // STEAM_STAT_TORCHERER
213 	std::make_pair("BARONY_ACH_MANY_PEDI_PALP", 50),		// STEAM_STAT_MANY_PEDI_PALP
214 	std::make_pair("BARONY_ACH_5000_SECOND_RULE", 50),      // STEAM_STAT_5000_SECOND_RULE
215 	std::make_pair("BARONY_ACH_SOCIAL_BUTTERFLY", 50),      // STEAM_STAT_SOCIAL_BUTTERFLY
216 	std::make_pair("BARONY_ACH_ROLL_THE_BONES", 50),        // STEAM_STAT_ROLL_THE_BONES
217 	std::make_pair("BARONY_ACH_COWBOY_FROM_HELL", 50),      // STEAM_STAT_COWBOY_FROM_HELL
218 	std::make_pair("BARONY_ACH_SELF_FLAGELLATION", 30),     // STEAM_STAT_SELF_FLAGELLATION
219 	std::make_pair("BARONY_ACH_CHOPPING_BLOCK", 50),		// STEAM_STAT_CHOPPING_BLOCK
220 	std::make_pair("BARONY_ACH_IF_YOU_LOVE_SOMETHING", 100),// STEAM_STAT_IF_YOU_LOVE_SOMETHING
221 	std::make_pair("BARONY_ACH_RAGE_AGAINST", 20),          // STEAM_STAT_RAGE_AGAINST
222 	std::make_pair("BARONY_ACH_GUERILLA_RADIO", 20),        // STEAM_STAT_GUERILLA_RADIO
223 	std::make_pair("BARONY_ACH_FASCIST", 50),				// STEAM_STAT_FASCIST,
224 	std::make_pair("BARONY_ACH_ITS_A_LIVING", 50),			// STEAM_STAT_ITS_A_LIVING,
225 	std::make_pair("BARONY_ACH_OVERCLOCKED", 600),			// STEAM_STAT_OVERCLOCKED
226 	std::make_pair("BARONY_ACH_NONE", 1),					// STEAM_STAT_BACK_TO_BASICS,
227 	std::make_pair("BARONY_ACH_EXTRA_CREDIT", 10),			// STEAM_STAT_EXTRA_CREDIT
228 	std::make_pair("BARONY_ACH_NONE", 1023),				// STEAM_STAT_EXTRA_CREDIT_LVLS,
229 	std::make_pair("BARONY_ACH_DIPLOMA", 10),				// STEAM_STAT_DIPLOMA
230 	std::make_pair("BARONY_ACH_NONE", 1023),				// STEAM_STAT_DIPLOMA_LVLS,
231 	std::make_pair("BARONY_ACH_NONE", 1)					// STEAM_STAT_TUTORIAL_ENTERED,
232 };
233 
234 typedef struct score_t
235 {
236 	Sint32 kills[NUMMONSTERS];
237 	Stat* stats;
238 	Sint32 classnum;
239 	Sint32 dungeonlevel;
240 	int victory;
241 
242 	Uint32 completionTime;
243 	bool conductPenniless;
244 	bool conductFoodless;
245 	bool conductVegetarian;
246 	bool conductIlliterate;
247 	Sint32 conductGameChallenges[NUM_CONDUCT_CHALLENGES];
248 	Sint32 gameStatistics[NUM_GAMEPLAY_STATISTICS];
249 } score_t;
250 extern list_t topscores;
251 extern list_t topscoresMultiplayer;
252 extern int victory;
253 
254 extern Uint32 completionTime;
255 extern bool conductPenniless;
256 extern bool conductFoodless;
257 extern bool conductVegetarian;
258 extern bool conductIlliterate;
259 extern list_t booksRead;
260 extern bool usedClass[NUMCLASSES];
261 extern bool usedRace[NUMRACES];
262 extern Uint32 loadingsavegame;
263 extern Sint32 conductGameChallenges[NUM_CONDUCT_CHALLENGES];
264 extern Sint32 gameStatistics[NUM_GAMEPLAY_STATISTICS];
265 extern std::vector<std::pair<Uint32, Uint32>> achievementRhythmOfTheKnightVec[MAXPLAYERS];
266 extern bool achievementStatusRhythmOfTheKnight[MAXPLAYERS];
267 extern std::pair<Uint32, Uint32> achievementThankTheTankPair[MAXPLAYERS];
268 extern bool achievementStatusBaitAndSwitch[MAXPLAYERS];
269 extern Uint32 achievementBaitAndSwitchTimer[MAXPLAYERS];
270 extern std::unordered_set<int> clientLearnedAlchemyIngredients;
271 extern bool achievementStatusThankTheTank[MAXPLAYERS];
272 extern std::vector<Uint32> achievementStrobeVec[MAXPLAYERS];
273 extern bool achievementStatusStrobe[MAXPLAYERS];
274 extern bool playerFailedRangedOnlyConduct[MAXPLAYERS];
275 extern bool achievementBrawlerMode;
276 extern bool achievementRangedMode[MAXPLAYERS];
277 
278 score_t* scoreConstructor();
279 void scoreDeconstructor(void* data);
280 int saveScore();
281 int totalScore(score_t* score);
282 void loadScore(int score);
283 void saveAllScores(const std::string& scoresfilename);
284 void loadAllScores(const std::string& scoresfilename);
285 extern int savegameCurrentFileIndex;
286 std::string setSaveGameFileName(bool singleplayer, bool followersFile, int saveIndex = savegameCurrentFileIndex);
287 int saveGame(int saveIndex = savegameCurrentFileIndex);
288 int loadGame(int player, int saveIndex = savegameCurrentFileIndex);
289 list_t* loadGameFollowers(int saveIndex = savegameCurrentFileIndex);
290 int deleteSaveGame(int gametype, int saveIndex = savegameCurrentFileIndex);
291 bool saveGameExists(bool singleplayer, int saveIndex = savegameCurrentFileIndex);
292 bool anySaveFileExists();
293 
294 char* getSaveGameName(bool singleplayer, int saveIndex = savegameCurrentFileIndex);
295 int getSaveGameType(bool singleplayer, int saveIndex = savegameCurrentFileIndex);
296 int getSaveGameClientnum(bool singleplayer, int saveIndex = savegameCurrentFileIndex);
297 Uint32 getSaveGameMapSeed(bool singleplayer, int saveIndex = savegameCurrentFileIndex);
298 Uint32 getSaveGameUniqueGameKey(bool singleplayer, int saveIndex = savegameCurrentFileIndex);
299 int getSaveGameVersionNum(bool singleplayer, int saveIndex = savegameCurrentFileIndex);
300 int getSavegameVersion(char checkstr[64]); // returns -1 on invalid version, otherwise converts to 3 digit int
301 void setDefaultPlayerConducts(); // init values for foodless, penniless etc.
302 void updatePlayerConductsInMainLoop(); // check and update conduct flags throughout game that don't require a specific action. (tracking gold, server flags etc...)
303 void updateGameplayStatisticsInMainLoop(); // check for achievement values for gameplay statistics.
304 void updateAchievementRhythmOfTheKnight(int player, Entity* target, bool playerIsHit);
305 void updateAchievementThankTheTank(int player, Entity* target, bool targetKilled);
306 void updateAchievementBaitAndSwitch(int player, bool isTeleporting);
307 static const int SAVE_GAMES_MAX = 10;
308 
309 class AchievementObserver
310 {
311 	int levelObserved = -1;
312 public:
313 	Uint32 playerUids[MAXPLAYERS] = { 0 };
314 	void getCurrentPlayerUids();
315 	bool updateOnLevelChange();
316 	void updateData();
317 	int checkUidIsFromPlayer(Uint32 uid);
318 	std::unordered_map<Uint32, std::unordered_map<int, std::pair<int,int>>> entityAchievementsToProcess; // uid of entity, achievement int, <ticks remaining, optional counter>
319 
320 	bool addEntityAchievementTimer(Entity* entity, int achievement, int ticks, bool resetTimerIfActive, int optionalIncrement);
321 
322 	void achievementTimersTickDown();
323 	void awardAchievementIfActive(int player, Entity* entity, int achievement);
324 	void awardAchievement(int player, int achievement);
325 	void printActiveAchievementTimers();
326 
327 	enum Achievement : int
328 	{
329 		BARONY_ACH_TELEFRAG = 1,
330 		BARONY_ACH_REAL_BOY,
331 		BARONY_ACH_COOP_ESCAPE_MINES,
332 		BARONY_ACH_SWINGERS,
333 		BARONY_ACH_COLD_BLOODED,
334 		BARONY_ACH_SOULLESS,
335 		BARONY_ACH_TRIBAL,
336 		BARONY_ACH_MANAGEMENT_TEAM,
337 		BARONY_ACH_SOCIOPATHS,
338 		BARONY_ACH_FACES_OF_DEATH,
339 		BARONY_ACH_SURVIVALISTS,
340 		BARONY_ACH_BOMBTRACK,
341 		BARONY_ACH_CALM_LIKE_A_BOMB,
342 		BARONY_ACH_CAUGHT_IN_A_MOSH,
343 		BARONY_ACH_PLEASE_HOLD,
344 		BARONY_ACH_FELL_BEAST,
345 		BARONY_ACH_STRUNG_OUT,
346 		BARONY_ACH_OHAI_MARK,
347 		BARONY_ACH_IRONIC_PUNISHMENT,
348 		BARONY_ACH_LEVITANT_LACKEY,
349 		BARONY_ACH_WONDERFUL_TOYS,
350 		BARONY_ACH_FLUTTERSHY,
351 		BARONY_ACH_IF_YOU_LOVE_SOMETHING,
352 		BARONY_ACH_COWBOY_FROM_HELL,
353 		BARONY_ACH_TRASH_COMPACTOR,
354 		BARONY_ACH_EXTRA_CREDIT,
355 		BARONY_ACH_DIPLOMA,
356 		BARONY_ACH_BACK_TO_BASICS,
357 		BARONY_ACH_FAST_LEARNER,
358 		BARONY_ACH_MASTER
359 	};
360 	enum AchievementEvent : int
361 	{
362 		ACH_EVENT_NONE,
363 		REAL_BOY_HUMAN_RECRUIT,
364 		REAL_BOY_SHOP,
365 		FORUM_TROLL_BREAK_WALL,
366 		FORUM_TROLL_RECRUIT_TROLL,
367 		FORUM_TROLL_FEAR,
368 		EXTRA_CREDIT_SECRET,
369 		DIPLOMA_LEVEL_COMPLETE,
370 		BACK_TO_BASICS_LEVEL_COMPLETE,
371 		FAST_LEARNER_TIME_UPDATE
372 	};
373 	void updatePlayerAchievement(int player, Achievement achievement, AchievementEvent achEvent);
bIsAchievementAllowedDuringTutorial(std::string achievementStr)374 	bool bIsAchievementAllowedDuringTutorial(std::string achievementStr)
375 	{
376 		if ( !achievementStr.compare("BARONY_ACH_TEACHABLE_MOMENT") )
377 		{
378 			return true;
379 		}
380 		if ( !achievementStr.compare("BARONY_ACH_MASTER") )
381 		{
382 			return true;
383 		}
384 		if ( !achievementStr.compare("BARONY_ACH_FAST_LEARNER") )
385 		{
386 			return true;
387 		}
388 		if ( !achievementStr.compare("BARONY_ACH_BACK_TO_BASICS") )
389 		{
390 			return true;
391 		}
392 		if ( !achievementStr.compare("BARONY_ACH_EXPELLED") )
393 		{
394 			return true;
395 		}
396 		if ( !achievementStr.compare("BARONY_ACH_EXTRA_CREDIT") )
397 		{
398 			return true;
399 		}
400 		if ( !achievementStr.compare("BARONY_ACH_DIPLOMA") )
401 		{
402 			return true;
403 		}
404 		return false;
405 	}
bIsStatisticAllowedDuringTutorial(SteamStatIndexes statistic)406 	bool bIsStatisticAllowedDuringTutorial(SteamStatIndexes statistic)
407 	{
408 		switch ( statistic )
409 		{
410 			case STEAM_STAT_EXTRA_CREDIT:
411 			case STEAM_STAT_EXTRA_CREDIT_LVLS:
412 			case STEAM_STAT_DIPLOMA:
413 			case STEAM_STAT_DIPLOMA_LVLS:
414 			case STEAM_STAT_TUTORIAL_ENTERED:
415 				return true;
416 				break;
417 			default:
418 				return false;
419 				break;
420 		}
421 	}
422 	class PlayerAchievements
423 	{
424 	public:
425 		bool caughtInAMosh = false;
426 		bool bombTrack = false;
427 		bool calmLikeABomb = false;
428 		bool strungOut = false;
429 		bool wonderfulToys = false;
430 		bool levitantLackey = false;
431 		bool flutterShy = false;
432 		bool gastricBypass = false;
433 		Uint32 ticksSpentOverclocked = 0;
434 		bool tradition = false;
435 		int traditionKills = 0;
436 		int torchererScrap = 0;
437 		int superShredder = 0;
438 		int fixerUpper = 0;
439 		int ifYouLoveSomething = 0;
440 		int socialButterfly = 0;
441 		int rollTheBones = 0;
442 		int trashCompactor = 0;
443 
444 		std::pair<int, int> realBoy;
445 		std::unordered_map<Uint32, int> caughtInAMoshTargets;
446 		std::vector<Uint32> strungOutTicks;
447 		std::unordered_set<Uint32> ironicPunishmentTargets;
448 		std::pair<real_t, real_t> flutterShyCoordinates;
449 		std::pair<int, Uint32> gastricBypassSpell;
450 		std::unordered_set<Uint32> rat5000secondRule;
451 
PlayerAchievements()452 		PlayerAchievements()
453 		{
454 			realBoy = std::make_pair(0, 0);
455 			gastricBypassSpell = std::make_pair(0, 0);
456 			flutterShyCoordinates = std::make_pair(0.0, 0.0);
457 		};
458 		bool checkPathBetweenObjects(Entity* player, Entity* target, int achievement);
459 		bool checkTraditionKill(Entity* player, Entity* target);
460 	} playerAchievements[MAXPLAYERS];
461 
462 	void clearPlayerAchievementData();
463 	void checkMapScriptsOnVariableSet();
464 	void updateGlobalStat(int index, int value = 1);
465 };
466 extern AchievementObserver achievementObserver;
467 
468 #ifdef STEAMWORKS
469 bool steamLeaderboardSetScore(score_t* score);
470 bool steamLeaderboardReadScore(int tags[CSteamLeaderboards::k_numLeaderboardTags]);
471 #endif // STEAMWORKS
472