public string GeneratePlayerPage(PlayerInfo pi) { //Program.Log("Generating player page for " + pi.name + " (" + pi.id + ")"); //Enable this for a lot of spam stringBuilder = new StringBuilder(); //Sort entries chronologically (oldest scores first) pi.entries.Sort((x, y) => (x.timestamp.CompareTo(y.timestamp))); //Get info ExtendedPlayerEntry latestEntry = pi.entries[pi.entries.Count - 1]; long totalFrames = 0; int normalClears = 0; int hardClears = 0; int specialClears = 0; int scVisits = 0; int coVisits = 0; bool doubleSpecial = false; List <Character> playedChars = new List <Character>(); for (int i = 0; i < pi.entries.Count; i++) { ExtendedPlayerEntry e = pi.entries[i]; totalFrames += e.runframes; switch (e.runend) { case RunEndCause.NormalClear: normalClears++; break; case RunEndCause.HardClear: hardClears++; break; case RunEndCause.SpecialClear: specialClears++; break; } if (e.level >= 19) { scVisits++; } if (e.level >= 23) { coVisits++; } //Accomplishment tracking if (i > 0 && e.runend == RunEndCause.SpecialClear) { if (pi.entries[i - 1].runend == RunEndCause.SpecialClear) { doubleSpecial = true; } } bool hasPlayedCharacter = false; for (int j = 0; j < playedChars.Count; j++) { if (playedChars[j] == pi.entries[i].character) { hasPlayedCharacter = true; } } if (!hasPlayedCharacter) { playedChars.Add(pi.entries[i].character); } } //Check for accomplishments List <Accomplishment> accomplishments = new List <Accomplishment>(); if (specialClears >= 10) { accomplishments.Add(new Accomplishment("Legend", "This player has reached 7-99 ten times!", "legend.png")); } if (pi.bestLevelRank == 1) { accomplishments.Add(new Accomplishment("#1 Depth", "This player has achieved rank #1 in Depth on a daily!", "1depth.png")); } if (pi.bestScoreRank == 1) { accomplishments.Add(new Accomplishment("#1 Score", "This player has achieved rank #1 in Score on a daily!", "1score.png")); } if (pi.bestHardTimeRank == 1) { accomplishments.Add(new Accomplishment("#1 Hard", "This player got first place in a Hard speedrun on a daily!", "1hard.png")); } if (pi.bestNormalTimeRank == 1) { accomplishments.Add(new Accomplishment("#1 Normal", "This player got first place in a Normal speedrun on a daily!", "1normal.png")); } if (pi.bestSpecialTimeRank == 1) { accomplishments.Add(new Accomplishment("#1 Special", "This player was the fastest to get a Special clear on a daily!", "1special.png")); } if (doubleSpecial) { accomplishments.Add(new Accomplishment("Consistent", "This player has reached 7-99 twice in a row!", "consistent.png")); } if (pi.bestSpecialTime != -1 && pi.bestSpecialTime < 116 * 60 * 60) { accomplishments.Add(new Accomplishment("Celeritas", "This player reached 7-99 within 1 hour and 56 minutes!", "celeritas.png")); } if (specialClears > 0) { accomplishments.Add(new Accomplishment("One with the Cosmos", "This player has reached 7-99!", "799.png")); } if (pi.bestScore > 2000000) { accomplishments.Add(new Accomplishment("Treasure Hunter", "This player has achieved a top score of over $2,000,000!", "2million.png")); } if (pi.bestHardTime != -1 && pi.bestHardTime < 20 * 60 * 60) { accomplishments.Add(new Accomplishment("brb killing primordial chaos", "This player has completed a Hard run in under 20 minutes!", "fasthard.png")); } if ((pi.bestNormalTime != -1 && pi.bestNormalTime < 8 * 60 * 60) || (pi.bestHardTime != -1 && pi.bestHardTime < 8 * 60 * 60)) { accomplishments.Add(new Accomplishment("Really Fast", "This player has completed a run in under 8 minutes!", "fastnormal.png")); } if (pi.topScoresAverage > 1000000) { accomplishments.Add(new Accomplishment("More like 'Palace of Treasure' am I right", "This player has a top 10 average score of over $1,000,000!", "million.png")); } if (coVisits >= 10) { accomplishments.Add(new Accomplishment("Astronaut", "This player has reached the Cosmic Ocean ten times!", "astronaut.png")); } if (pi.entries.Count >= 365) { accomplishments.Add(new Accomplishment("Yearly Challenge", "This player has participated 365 times!", "year.png")); } if (playedChars.Count == 20) { accomplishments.Add(new Accomplishment("I Main Random", "This player has played with every character!", "allchars.png")); } //Write header WriteHeader(PageType.Player, pi.name); //Return link stringBuilder.AppendLine("<center><a href=\"depth.html\">[Click here to return to leaderboard listings]</a><br /><br />"); //Name(s) stringBuilder.Append("<font size=\"7\">"); stringBuilder.Append(pi.name); stringBuilder.Append("</font>"); BR(); //Filter duplicate alternate names for (int i = 0; i < pi.previousNames.Count; i++) { if (pi.previousNames[i] == pi.name) { pi.previousNames.RemoveAt(i); i--; continue; } for (int j = 0; j < pi.previousNames.Count; j++) { if (i == j) { continue; } if (pi.previousNames[i] == pi.previousNames[j]) { pi.previousNames.RemoveAt(j); j--; } } } //List alternate names for (int i = 0; i < pi.previousNames.Count; i++) { stringBuilder.Append("aka "); stringBuilder.Append(pi.previousNames[i]); BR(); } //Last used character stringBuilder.Append("<table><tr><td class=\"c"); stringBuilder.Append(Convert.ToString((int)latestEntry.character, 16).PadLeft(2, '0')); stringBuilder.Append("\"/></tr></table>"); BR(); //Info PlayerAddition addition = null; if (Program.additions.ContainsKey(pi.id)) { addition = Program.additions[pi.id]; } if (addition != null) { stringBuilder.Append(addition.html); BR(); } if (latestEntry.platform == Platform.Steam) { stringBuilder.Append("<a href=\"https://steamcommunity.com/profiles/"); stringBuilder.Append(pi.id); stringBuilder.AppendLine("\">Visit Steam profile</a><br />"); } BR(); //Accomplishments if (accomplishments.Count > 0) { stringBuilder.AppendLine("<table>"); for (int i = 0; i < accomplishments.Count; i++) { WriteKeyValue("<img src=\"" + accomplishments[i].icon + "\">", "<b>" + accomplishments[i].name + "</b>: " + accomplishments[i].description); } stringBuilder.AppendLine("</table><br />"); } //From here on, do not show links until hovered stringBuilder.AppendLine("<div class=\"hidelink\">"); //General stats stringBuilder.AppendLine("<font size=\"5\">General statistics</font><br />"); stringBuilder.AppendLine("<table>"); WriteKeyValue("Runs", pi.entries.Count); WriteKeyValue("Total playtime", PlayerEntry.GetTime(totalFrames)); WriteKeyValue("Normal clears", normalClears); WriteKeyValue("Sunken City visits", scVisits); WriteKeyValue("Hard clears", hardClears); WriteKeyValue("CO visits", coVisits); WriteKeyValue("Special clears", specialClears); stringBuilder.AppendLine("</table><br /><br />"); //Top average scores stringBuilder.AppendLine("<font size=\"5\">Top averages</font><br />"); stringBuilder.AppendLine("<table>"); int wholePart = (int)Math.Floor(pi.topLevelsAverage); float fraction = pi.topLevelsAverage - wholePart; stringBuilder.Append("<tr><td><b>Top 10 average depth</b></td><td>"); stringBuilder.Append(PlayerEntry.GetLevel(wholePart)); stringBuilder.Append("<font size=\"1\">."); string fractionalString = Convert.ToString(Math.Round(fraction, 3)); if (fractionalString.Length < 2) { fractionalString = "000"; } else { fractionalString = fractionalString.Substring(2).PadRight(3, '0'); } stringBuilder.Append(fractionalString); stringBuilder.Append("</font>"); stringBuilder.AppendLine("</td></tr>"); WriteKeyValue("Top 10 average score", PlayerEntry.GetScore(pi.topScoresAverage)); WriteKeyValue("Top 5 average time", PlayerEntry.GetTime(pi.topTimesAverage)); stringBuilder.AppendLine("</table><br /><br />"); //Best rankings stringBuilder.AppendLine("<font size=\"5\">Best rankings</font><br />"); stringBuilder.AppendLine("<table>"); WriteTimestampedValue("Best depth ranking", pi.bestLevelRank, pi.bestLevelRankDates); WriteTimestampedValue("Best score ranking", pi.bestScoreRank, pi.bestScoreRankDates); if (pi.bestNormalTimeRankDates.Count == 0) { WriteKeyValue("Best Normal ranking", "<i>N/A</i>"); } else { WriteTimestampedValue("Best Normal ranking", pi.bestNormalTimeRank, pi.bestNormalTimeRankDates); } if (pi.bestHardTimeRankDates.Count == 0) { WriteKeyValue("Best Hard ranking", "<i>N/A</i>"); } else { WriteTimestampedValue("Best Hard ranking", pi.bestHardTimeRank, pi.bestHardTimeRankDates); } if (pi.bestSpecialTimeRankDates.Count == 0) { WriteKeyValue("Best Special ranking", "<i>N/A</i>"); } else { WriteTimestampedValue("Best Special ranking", pi.bestSpecialTimeRank, pi.bestSpecialTimeRankDates); } stringBuilder.AppendLine("</table><br /><br />"); //Top results stringBuilder.AppendLine("<font size=\"5\">Top results</font><br />"); stringBuilder.AppendLine("<table>"); WriteTimestampedValue("Best depth", PlayerEntry.GetLevel(pi.bestLevel), pi.bestLevelDates); WriteTimestampedValue("Best score", PlayerEntry.GetScore(pi.bestScore), pi.bestScoreDate); if (pi.bestNormalTime == -1) { WriteKeyValue("Fastest Normal clear", "<i>N/A</i>"); } else { WriteTimestampedValue("Fastest Normal clear", PlayerEntry.GetTime(pi.bestNormalTime), pi.bestNormalTimeDate); } if (pi.bestHardTime == -1) { WriteKeyValue("Fastest Hard clear", "<i>N/A</i>"); } else { WriteTimestampedValue("Fastest Hard clear", PlayerEntry.GetTime(pi.bestHardTime), pi.bestHardTimeDate); } if (pi.bestSpecialTime == -1) { WriteKeyValue("Fastest Special clear", "<i>N/A</i>"); } else { WriteTimestampedValue("Fastest Special clear", PlayerEntry.GetTime(pi.bestSpecialTime), pi.bestSpecialTimeDate); } stringBuilder.AppendLine("</table><br /><br />"); //All results pi.entries.Sort((x, y) => (y.timestamp.CompareTo(x.timestamp))); //Sort in reverse chronological order for display stringBuilder.AppendLine("<font size=\"5\">All results</font><br />"); stringBuilder.AppendLine("<table style=\"min-width: 0.5em;\">"); for (int i = 0; i < pi.entries.Count; i++) { ExtendedPlayerEntry epe = pi.entries[i]; bool clear = (epe.runend == RunEndCause.NormalClear || epe.runend == RunEndCause.HardClear || epe.runend == RunEndCause.SpecialClear); stringBuilder.Append("<tr><td>"); string tsString = Program.IntTimestampToString(epe.timestamp); stringBuilder.Append(" <a href=\""); stringBuilder.Append(tsString); stringBuilder.Append("_depth.html\">"); stringBuilder.Append(tsString); stringBuilder.Append("</a> "); stringBuilder.Append("</td><td /><td class=\"c"); stringBuilder.Append(Convert.ToString((int)epe.character, 16).PadLeft(2, '0')); stringBuilder.Append("\" /><td /><td>#"); stringBuilder.Append(epe.levelRank); stringBuilder.Append("</td><td"); if (clear) { stringBuilder.Append(" class=\"clear\">"); } else if (pi.entries[i].level >= COSMIC_OCEAN) { stringBuilder.Append(" class=\"co\">"); } else { stringBuilder.Append(">"); } stringBuilder.Append(epe.GetLevel()); stringBuilder.Append("</td><td /><td>#"); stringBuilder.Append(epe.scoreRank); stringBuilder.Append("</td><td>$"); stringBuilder.Append(epe.GetScore()); if (clear) { stringBuilder.Append("</td><td /><td>#"); switch (epe.runend) { case RunEndCause.NormalClear: stringBuilder.Append(epe.normalTimeRank); break; case RunEndCause.HardClear: stringBuilder.Append(epe.hardTimeRank); break; case RunEndCause.SpecialClear: stringBuilder.Append(epe.specialTimeRank); break; } stringBuilder.Append("</td><td>"); stringBuilder.Append(epe.GetTime()); } stringBuilder.AppendLine("</td></tr>"); } stringBuilder.AppendLine("</table><br />"); //Finish stringBuilder.AppendLine("</div>"); //hidelink end WriteFooter(PageType.Player, true, Convert.ToString((long)pi.id, 16).PadLeft(16, '0') + ".json"); //Write to file return(stringBuilder.ToString()); }
public int topTimesAverage = 9 * 60 * 60 * 60 + 59 * 60 * 60 + 59 * 60; //9:59:99, also just round it public void AddEntry(ExtendedPlayerEntry epe) { //Add entry ExtendedPlayerEntry prevEntry = GetEntry(epe.timestamp); if (prevEntry != null) { entries.Remove(prevEntry); indexedEntries.Remove(prevEntry.timestamp); } entries.Add(epe); indexedEntries.Add(epe.timestamp, epe); //Set ID in case it hasn't been set yet this.id = epe.id; //Adjust name in case it's changed if (this.name != epe.name) { if (this.name != "Unknown player") { this.previousNames.Add(this.name); } this.name = epe.name; } //Adjust best level if (epe.level > this.bestLevel) { this.bestLevel = epe.level; this.bestLevelDates.Clear(); this.bestLevelDates.Add(epe.timestamp); } else if (epe.level == this.bestLevel) { bool alreadyHas = false; for (int i = 0; i < this.bestLevelDates.Count; i++) { if (this.bestLevelDates[i] == epe.timestamp) { alreadyHas = true; } } if (!alreadyHas) { this.bestLevelDates.Add(epe.timestamp); } } //Adjust best score if (epe.score > this.bestScore) { this.bestScore = epe.score; this.bestScoreDate = epe.timestamp; } //Adjust best times switch (epe.runend) { case RunEndCause.NormalClear: if (epe.runframes < this.bestNormalTime || this.bestNormalTime == -1) { this.bestNormalTime = epe.runframes; this.bestNormalTimeDate = epe.timestamp; } break; case RunEndCause.HardClear: if (epe.runframes < this.bestHardTime || this.bestHardTime == -1) { this.bestHardTime = epe.runframes; this.bestHardTimeDate = epe.timestamp; } break; case RunEndCause.SpecialClear: if (epe.runframes < this.bestSpecialTime || this.bestSpecialTime == -1) { this.bestSpecialTime = epe.runframes; this.bestSpecialTimeDate = epe.timestamp; } break; } //Adjust best level rank if (epe.levelRank <= this.bestLevelRank || this.bestLevelRank == -1) { if (epe.levelRank < this.bestLevelRank) { this.bestLevelRankDates.Clear(); } this.bestLevelRank = epe.levelRank; bool alreadyHas = false; for (int i = 0; i < this.bestLevelRankDates.Count; i++) { if (this.bestLevelRankDates[i] == epe.timestamp) { alreadyHas = true; } } if (!alreadyHas) { this.bestLevelRankDates.Add(epe.timestamp); } } //Adjust best score rank if (epe.scoreRank <= this.bestScoreRank || this.bestScoreRank == -1) { if (epe.scoreRank < this.bestScoreRank) { this.bestScoreRankDates.Clear(); } this.bestScoreRank = epe.scoreRank; bool alreadyHas = false; for (int i = 0; i < this.bestScoreRankDates.Count; i++) { if (this.bestScoreRankDates[i] == epe.timestamp) { alreadyHas = true; } } if (!alreadyHas) { this.bestScoreRankDates.Add(epe.timestamp); } } //Adjust best time ranks if (epe.normalTimeRank != -1 && (epe.normalTimeRank <= this.bestNormalTimeRank || this.bestNormalTimeRank == -1)) { if (epe.normalTimeRank < this.bestNormalTimeRank) { this.bestNormalTimeRankDates.Clear(); } this.bestNormalTimeRank = epe.normalTimeRank; bool alreadyHas = false; for (int i = 0; i < this.bestNormalTimeRankDates.Count; i++) { if (this.bestNormalTimeRankDates[i] == epe.timestamp) { alreadyHas = true; } } if (!alreadyHas) { this.bestNormalTimeRankDates.Add(epe.timestamp); } } if (epe.hardTimeRank != -1 && (epe.hardTimeRank <= this.bestHardTimeRank || this.bestHardTimeRank == -1)) { if (epe.hardTimeRank < this.bestHardTimeRank) { this.bestHardTimeRankDates.Clear(); } this.bestHardTimeRank = epe.hardTimeRank; bool alreadyHas = false; for (int i = 0; i < this.bestHardTimeRankDates.Count; i++) { if (this.bestHardTimeRankDates[i] == epe.timestamp) { alreadyHas = true; } } if (!alreadyHas) { this.bestHardTimeRankDates.Add(epe.timestamp); } } if (epe.specialTimeRank != -1 && (epe.specialTimeRank <= this.bestSpecialTimeRank || this.bestSpecialTimeRank == -1)) { if (epe.specialTimeRank < this.bestSpecialTimeRank) { this.bestSpecialTimeRankDates.Clear(); } this.bestSpecialTimeRank = epe.specialTimeRank; bool alreadyHas = false; for (int i = 0; i < this.bestSpecialTimeRankDates.Count; i++) { if (this.bestSpecialTimeRankDates[i] == epe.timestamp) { alreadyHas = true; } } if (!alreadyHas) { this.bestSpecialTimeRankDates.Add(epe.timestamp); } } //Get top entries List <ExtendedPlayerEntry> adjustedEntries = null; if (entries.Count > 9) { adjustedEntries = entries; } else { adjustedEntries = new List <ExtendedPlayerEntry>(entries); } int num = 1; while (adjustedEntries.Count < 10) { adjustedEntries.Add(new ExtendedPlayerEntry(new PlayerEntry(), 0, 0, num)); //Avoid duplicate timestamps num++; } //Top 10 depths adjustedEntries.Sort((x, y) => (y.level.CompareTo(x.level))); topLevels.Clear(); topLevelsAverage = 0; for (int i = 0; i < 10; i++) { topLevels.Add(adjustedEntries[i].timestamp); topLevelsAverage += adjustedEntries[i].level; } topLevelsAverage /= 10f; //Top 10 scores adjustedEntries.Sort((x, y) => (y.score.CompareTo(x.score))); topScores.Clear(); topScoresAverage = 0; for (int i = 0; i < 10; i++) { topScores.Add(adjustedEntries[i].timestamp); topScoresAverage += adjustedEntries[i].score; } topScoresAverage = Convert.ToInt32(Math.Round((float)topScoresAverage / 10f)); //Top 5 times List <ExtendedPlayerEntry> normalClears = new List <ExtendedPlayerEntry>(); List <ExtendedPlayerEntry> hardClears = new List <ExtendedPlayerEntry>(); List <ExtendedPlayerEntry> specialClears = new List <ExtendedPlayerEntry>(); List <ExtendedPlayerEntry> allClears = new List <ExtendedPlayerEntry>(); for (int i = 0; i < adjustedEntries.Count; i++) { switch (adjustedEntries[i].runend) { case RunEndCause.NormalClear: normalClears.Add(adjustedEntries[i]); allClears.Add(adjustedEntries[i]); break; case RunEndCause.HardClear: hardClears.Add(adjustedEntries[i]); allClears.Add(adjustedEntries[i]); break; case RunEndCause.SpecialClear: specialClears.Add(adjustedEntries[i]); allClears.Add(adjustedEntries[i]); break; } } while (allClears.Count < 5) { allClears.Add(new ExtendedPlayerEntry(new PlayerEntry(), 0, 0, 0)); } allClears.Sort((x, y) => (x.runframes.CompareTo(y.runframes))); topTimes.Clear(); topTimesAverage = 0; for (int i = 0; i < 5; i++) { topTimes.Add(allClears[i].timestamp); topTimesAverage += allClears[i].runframes; } topTimesAverage = Convert.ToInt32(Math.Round((float)topTimesAverage / 5f)); }