Add highscores and best times.

This commit is contained in:
SilicaAndPina 2020-12-27 15:42:01 +13:00
parent 0c99624f63
commit de9dfaf362
9 changed files with 291 additions and 37 deletions

View file

@ -91,6 +91,15 @@
"end_of_meta":"^Z", "end_of_meta":"^Z",
"back_to_map":"^M", "back_to_map":"^M",
"long_full_line":"^L", "long_full_line":"^L",
"highscores":{
"header_meta":"^ATMini-Game Rankings^H",
"highscore_format":"<B><font color='#000088'>%GAMETITLE%</font></B> Rank: <B>#%RANKING%</B> With: %SCORE% points (%TOTALPLAYS% plays)<BR>",
"besttime_format":"<B><font color='#000088'>%GAMETITLE%</font></B> Rank: <B>#%RANKING%</B> With: %SCORE% time score (%TOTALPLAYS% plays)<BR>",
"game_highscore_header":"<B>Top 20 High Scores for %GAMETITLE%</B><BR>",
"game_highscore_format":"#%RANKING%: %SCORE% points -- %USERNAME% [played %TOTALPLAYS% times]<BR>",
"game_besttime_header":"<B>Top 20 Best Times for %GAMETITLE%</B><BR>",
"game_besttime_format":"#%RANKING% Best Time: %SCORE% sec -- %USERNAME% [played %TOTALPLAYS% times]<BR>"
},
"quest_log":{ "quest_log":{
"header_meta":"^ATYour Horse Isle Adventure Log^H", "header_meta":"^ATYour Horse Isle Adventure Log^H",
"quest_format":"%TITLE% (%QUESTPOINTS%qp) [%DIFFICULTY%] %COMPLETION%<BR>", "quest_format":"%TITLE% (%QUESTPOINTS%qp) [%DIFFICULTY%] %COMPLETION%<BR>",

View file

@ -163,6 +163,17 @@ namespace HISP.Game
public static string SellButton; public static string SellButton;
public static string SellAllButton; public static string SellAllButton;
// Highscore List
public static string HighscoreHeaderMeta;
public static string HighscoreFormat;
public static string BestTimeFormat;
public static string GameBestTimeFormat;
public static string GameBestTimeHeaderFormat;
public static string GameHighScoreHeaderFormat;
public static string GameHighScoreFormat;
// Shop // Shop
public static string ThingsIAmSelling; public static string ThingsIAmSelling;
public static string ThingsYouSellMe; public static string ThingsYouSellMe;
@ -229,6 +240,30 @@ namespace HISP.Game
// Click // Click
public static string NothingInterestingHere; public static string NothingInterestingHere;
public static string FormatBestTimeHeader(string gameName)
{
return GameBestTimeHeaderFormat.Replace("%GAMETITLE%", gameName);
}
public static string FormatBestTimeListEntry(int ranking, int score, string username, int totalplays)
{
return GameBestTimeFormat.Replace("%RANKING%", ranking.ToString("N0")).Replace("%SCORE%", score.ToString().Insert(score.ToString().Length - 2, ".")).Replace("%USERNAME%", username).Replace("%TOTALPLAYS%", totalplays.ToString("N0"));
}
public static string FormatHighscoreHeader(string gameName)
{
return GameHighScoreHeaderFormat.Replace("%GAMETITLE%", gameName);
}
public static string FormatHighscoreListEntry(int ranking, int score, string username, int totalplays)
{
return GameHighScoreFormat.Replace("%RANKING%", ranking.ToString("N0")).Replace("%SCORE%", score.ToString("N0")).Replace("%USERNAME%", username).Replace("%TOTALPLAYS%", totalplays.ToString("N0"));
}
public static string FormatHighscoreStat(string gameTitle, int ranking, int score, int totalplays)
{
return HighscoreFormat.Replace("%GAMETITLE%", gameTitle).Replace("%RANKING%", ranking.ToString("N0")).Replace("%SCORE%", score.ToString("N0")).Replace("%TOTALPLAYS%", totalplays.ToString("N0"));
}
public static string FormatBestTimeStat(string gameTitle, int ranking, int score, int totalplays)
{
return BestTimeFormat.Replace("%GAMETITLE%", gameTitle).Replace("%RANKING%", ranking.ToString("N0")).Replace("%SCORE%", score.ToString()).Replace("%TOTALPLAYS%", totalplays.ToString("N0"));
}
public static string FormatMoneyEarnedMessage(int money) public static string FormatMoneyEarnedMessage(int money)
{ {
return YouEarnedMoneyFormat.Replace("%MONEY%", money.ToString("N0")); return YouEarnedMoneyFormat.Replace("%MONEY%", money.ToString("N0"));

View file

@ -225,7 +225,6 @@ namespace HISP.Game
return message; return message;
} }
public static string SelectPlayerStatFormat(int statValue) public static string SelectPlayerStatFormat(int statValue)
{ {
int curValue = 1000; int curValue = 1000;
@ -240,7 +239,55 @@ namespace HISP.Game
} }
throw new Exception("A mathematically impossible error occured. please check wether the laws of physics still apply."); throw new Exception("A mathematically impossible error occured. please check wether the laws of physics still apply.");
} }
public static string BuildTopHighscores(string gameName)
{
Highscore.HighscoreTableEntry[] scores = Database.GetTopScores(gameName, 20);
if (scores.Length <= 0)
return "No scores recorded.";
string message = "";
message += Messages.FormatHighscoreHeader(gameName);
for (int i = 0; i < scores.Length; i++)
{
message += Messages.FormatHighscoreListEntry(i+1, scores[i].Score, Database.GetUsername(scores[i].UserId), scores[i].TimesPlayed);
}
message += Messages.BackToMap;
message += Messages.MetaTerminator;
return message;
}
public static string BuildTopTimes(string gameName)
{
Highscore.HighscoreTableEntry[] scores = Database.GetTopScores(gameName, 20);
if (scores.Length <= 0)
return "No times recorded.";
string message = "";
message += Messages.FormatBestTimeHeader(gameName);
for (int i = 0; i < scores.Length; i++)
{
message += Messages.FormatBestTimeListEntry(i+1, scores[i].Score, Database.GetUsername(scores[i].UserId), scores[i].TimesPlayed);
}
message += Messages.BackToMap;
message += Messages.MetaTerminator;
return message;
}
public static string BuildMinigameRankingsForUser(User user)
{
string message = Messages.HighscoreHeaderMeta;
foreach(Highscore.HighscoreTableEntry highscore in user.Highscores.HighscoreList)
{
if (highscore.Type == "SCORE")
message += Messages.FormatHighscoreStat(highscore.GameName, Database.GetRanking(highscore.Score, highscore.GameName), highscore.Score, highscore.TimesPlayed);
else if(highscore.Type == "TIME")
message += Messages.FormatBestTimeStat(highscore.GameName, Database.GetRanking(highscore.Score, highscore.GameName), highscore.Score, highscore.TimesPlayed);
}
message += Messages.BackToMap;
message += Messages.MetaTerminator;
return message;
}
public static string BuildPrivateNotes(User user) public static string BuildPrivateNotes(User user)
{ {
string message = ""; string message = "";

View file

@ -1,31 +1,106 @@
using HISP.Server; using HISP.Server;
using System.Collections.Generic;
namespace HISP.Player namespace HISP.Player
{ {
class Highscore class Highscore
{ {
public static bool RegisterHighscore(int playerId, string gameTitle, int score, bool time) public class HighscoreTableEntry
{
public int UserId;
public string GameName;
public int Wins;
public int Looses;
public int TimesPlayed;
public int Score;
public string Type;
}
public HighscoreTableEntry[] HighscoreList
{
get
{
return highScoreList.ToArray();
}
}
private User baseUser;
private List<HighscoreTableEntry> highScoreList = new List<HighscoreTableEntry>();
public Highscore(User user)
{
baseUser = user;
HighscoreTableEntry[] highscores = Database.GetPlayerHighScores(user.Id);
foreach (HighscoreTableEntry highscore in highscores)
highScoreList.Add(highscore);
}
public HighscoreTableEntry GetHighscore(string gameTitle)
{
foreach (HighscoreTableEntry highscore in HighscoreList)
{
if (highscore.GameName == gameTitle)
{
return highscore;
}
}
throw new KeyNotFoundException("Highscore for " + gameTitle + " Not found.");
}
public bool HasHighscore(string gameTitle)
{
foreach(HighscoreTableEntry highscore in HighscoreList)
{
if(highscore.GameName == gameTitle)
{
return true;
}
}
return false;
}
public bool UpdateHighscore(string gameTitle, int score, bool time)
{ {
bool isNewScore = true; bool isNewScore = true;
if (!Database.PlayerHasHighscore(playerId, gameTitle)) if (!HasHighscore(gameTitle))
{ {
Database.AddNewHighscore(playerId, gameTitle, score, time ? "TIME" : "SCORE"); string type = time ? "TIME" : "SCORE";
Database.AddNewHighscore(baseUser.Id, gameTitle, score, type);
HighscoreTableEntry newHighscore = new HighscoreTableEntry();
newHighscore.UserId = baseUser.Id;
newHighscore.GameName = gameTitle;
newHighscore.Wins = 0;
newHighscore.Looses = 0;
newHighscore.TimesPlayed = 1;
newHighscore.Score = score;
newHighscore.Type = type;
highScoreList.Add(newHighscore);
return isNewScore; return isNewScore;
} }
else else
{ {
int currentScore = Database.GetHighscore(playerId, gameTitle); int currentScore = GetHighscore(gameTitle).Score;
if (score < currentScore) if (score < currentScore)
{ {
score = currentScore; score = currentScore;
isNewScore = false; isNewScore = false;
} }
Database.UpdateHighscore(playerId, gameTitle, score); Database.UpdateHighscore(baseUser.Id, gameTitle, score);
for(int i = 0; i < highScoreList.Count; i++)
{
if(highScoreList[i].GameName == gameTitle)
{
highScoreList[i].TimesPlayed += 1;
highScoreList[i].Score = score;
}
}
return isNewScore; return isNewScore;
} }
} }
} }
} }

View file

@ -39,6 +39,7 @@ namespace HISP.Player
public Npc.NpcEntry LastTalkedToNpc; public Npc.NpcEntry LastTalkedToNpc;
public Shop LastShoppedAt; public Shop LastShoppedAt;
public PlayerQuests Quests; public PlayerQuests Quests;
public Highscore Highscores;
public int FreeMinutes public int FreeMinutes
{ {
get get
@ -372,7 +373,7 @@ namespace HISP.Player
Gender = Database.GetGender(UserId); Gender = Database.GetGender(UserId);
MailBox = new Mailbox(this); MailBox = new Mailbox(this);
Highscores = new Highscore(this);
// Generate SecCodes // Generate SecCodes

View file

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using MySqlConnector; using MySqlConnector;
using HISP.Game; using HISP.Game;
using HISP.Player;
namespace HISP.Server namespace HISP.Server
{ {
@ -1688,22 +1689,6 @@ namespace HISP.Server
} }
} }
public static bool PlayerHasHighscore(int playerId, string gameTitle)
{
using (MySqlConnection db = new MySqlConnection(ConnectionString))
{
db.Open();
MySqlCommand sqlCommand = db.CreateCommand();
sqlCommand.CommandText = "SELECT COUNT(1) FROM Leaderboards WHERE playerId=@playerId AND minigame=@gameTitle";
sqlCommand.Parameters.AddWithValue("@playerId", playerId);
sqlCommand.Parameters.AddWithValue("@gameTitle", gameTitle);
sqlCommand.Prepare();
int count = Convert.ToInt32(sqlCommand.ExecuteScalar());
sqlCommand.Dispose();
return count >= 1;
}
}
public static void AddNewHighscore(int playerId, string gameTitle, int score, string type) public static void AddNewHighscore(int playerId, string gameTitle, int score, string type)
{ {
using (MySqlConnection db = new MySqlConnection(ConnectionString)) using (MySqlConnection db = new MySqlConnection(ConnectionString))
@ -1724,20 +1709,90 @@ namespace HISP.Server
} }
} }
public static int GetHighscore(int playerId, string gameTitle) public static Highscore.HighscoreTableEntry[] GetPlayerHighScores(int playerId)
{ {
List<Highscore.HighscoreTableEntry> entires = new List<Highscore.HighscoreTableEntry>();
using (MySqlConnection db = new MySqlConnection(ConnectionString)) using (MySqlConnection db = new MySqlConnection(ConnectionString))
{ {
db.Open(); db.Open();
MySqlCommand sqlCommand = db.CreateCommand(); MySqlCommand sqlCommand = db.CreateCommand();
sqlCommand.CommandText = "SELECT score FROM Leaderboards WHERE playerId=@playerId AND minigame=@gameTitle"; sqlCommand.CommandText = "SELECT * FROM leaderboards WHERE playerId=@playerId ORDER BY score ASC";
sqlCommand.Parameters.AddWithValue("@playerId", playerId); sqlCommand.Parameters.AddWithValue("@playerId", playerId);
sqlCommand.Parameters.AddWithValue("@gameTitle", gameTitle);
sqlCommand.Prepare(); sqlCommand.Prepare();
int score = Convert.ToInt32(sqlCommand.ExecuteScalar()); MySqlDataReader reader = sqlCommand.ExecuteReader();
while (reader.Read())
{
Highscore.HighscoreTableEntry highscoreEntry = new Highscore.HighscoreTableEntry();
highscoreEntry.UserId = reader.GetInt32(0);
highscoreEntry.GameName = reader.GetString(1);
highscoreEntry.Wins = reader.GetInt32(2);
highscoreEntry.Looses = reader.GetInt32(3);
highscoreEntry.TimesPlayed = reader.GetInt32(4);
highscoreEntry.Score = reader.GetInt32(5);
highscoreEntry.Type = reader.GetString(6);
entires.Add(highscoreEntry);
}
sqlCommand.Dispose(); sqlCommand.Dispose();
return score; return entires.ToArray();
}
}
public static Highscore.HighscoreTableEntry[] GetTopScores(string gameTitle, int limit)
{
List<Highscore.HighscoreTableEntry> entires = new List<Highscore.HighscoreTableEntry>();
using (MySqlConnection db = new MySqlConnection(ConnectionString))
{
db.Open();
MySqlCommand sqlCommand = db.CreateCommand();
sqlCommand.CommandText = "SELECT * FROM leaderboards WHERE minigame=@gameTitle ORDER BY score ASC LIMIT @limit";
sqlCommand.Parameters.AddWithValue("@gameTitle", gameTitle);
sqlCommand.Parameters.AddWithValue("@limit", limit);
sqlCommand.Prepare();
MySqlDataReader reader = sqlCommand.ExecuteReader();
while(reader.Read())
{
Highscore.HighscoreTableEntry highscoreEntry = new Highscore.HighscoreTableEntry();
highscoreEntry.UserId = reader.GetInt32(0);
highscoreEntry.GameName = gameTitle;
highscoreEntry.Wins = reader.GetInt32(2);
highscoreEntry.Looses = reader.GetInt32(3);
highscoreEntry.TimesPlayed = reader.GetInt32(4);
highscoreEntry.Score = reader.GetInt32(5);
highscoreEntry.Type = reader.GetString(6);
entires.Add(highscoreEntry);
}
sqlCommand.Dispose();
return entires.ToArray();
}
}
public static int GetRanking(int score, string gameTitle)
{
using (MySqlConnection db = new MySqlConnection(ConnectionString))
{
db.Open();
MySqlCommand sqlCommand = db.CreateCommand();
sqlCommand.CommandText = "SELECT DISTINCT score FROM leaderboards WHERE minigame=@gameTitle ORDER BY score ASC";
sqlCommand.Parameters.AddWithValue("@gameTitle", gameTitle);
sqlCommand.Prepare();
MySqlDataReader reader = sqlCommand.ExecuteReader();
int i = 1;
while(reader.Read())
{
if (reader.GetInt32(0) == score)
break;
i++;
}
sqlCommand.Dispose();
return i;
} }
} }
public static void UpdateHighscore(int playerId, string gameTitle, int score) public static void UpdateHighscore(int playerId, string gameTitle, int score)

View file

@ -550,6 +550,17 @@ namespace HISP.Server
Messages.NoPitchforkMeta = gameData.messages.meta.hay_pile.no_pitchfork; Messages.NoPitchforkMeta = gameData.messages.meta.hay_pile.no_pitchfork;
Messages.HasPitchforkMeta = gameData.messages.meta.hay_pile.pitchfork; Messages.HasPitchforkMeta = gameData.messages.meta.hay_pile.pitchfork;
// Highscore
Messages.HighscoreHeaderMeta = gameData.messages.meta.highscores.header_meta;
Messages.HighscoreFormat = gameData.messages.meta.highscores.highscore_format;
Messages.BestTimeFormat = gameData.messages.meta.highscores.besttime_format;
Messages.GameHighScoreHeaderFormat = gameData.messages.meta.highscores.game_highscore_header;
Messages.GameHighScoreFormat = gameData.messages.meta.highscores.game_highscore_format;
Messages.GameBestTimeHeaderFormat = gameData.messages.meta.highscores.game_besttime_header;
Messages.GameBestTimeFormat = gameData.messages.meta.highscores.game_besttime_format;
// Sec Codes // Sec Codes

View file

@ -158,6 +158,10 @@ namespace HISP.Server
metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildPrivateNotes(sender.LoggedinUser)); metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildPrivateNotes(sender.LoggedinUser));
sender.SendPacket(metaPacket); sender.SendPacket(metaPacket);
break; break;
case 20:
metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildMinigameRankingsForUser(sender.LoggedinUser));
sender.SendPacket(metaPacket);
break;
default: default:
Logger.ErrorPrint("Dynamic button #" + buttonId + " unknown..."); Logger.ErrorPrint("Dynamic button #" + buttonId + " unknown...");
break; break;
@ -349,7 +353,7 @@ namespace HISP.Server
return; return;
} }
bool newHighscore = Highscore.RegisterHighscore(sender.LoggedinUser.Id, gameTitle, value, time); bool newHighscore = sender.LoggedinUser.Highscores.UpdateHighscore(gameTitle, value, time);
if (newHighscore && !time) if (newHighscore && !time)
{ {
byte[] chatPacket = PacketBuilder.CreateChat(Messages.FormatHighscoreBeatenMessage(value), PacketBuilder.CHAT_BOTTOM_RIGHT); byte[] chatPacket = PacketBuilder.CreateChat(Messages.FormatHighscoreBeatenMessage(value), PacketBuilder.CHAT_BOTTOM_RIGHT);
@ -530,7 +534,21 @@ namespace HISP.Server
return; return;
} }
} }
else if(method == PacketBuilder.PLAYERINFO_HIGHSCORES_LIST)
{
string packetStr = Encoding.UTF8.GetString(packet);
string gameName = packetStr.Substring(2, packetStr.Length - 4);
byte[] metaTag = PacketBuilder.CreateMetaPacket(Meta.BuildTopHighscores(gameName));
sender.SendPacket(metaTag);
}
else if (method == PacketBuilder.PLAYERINFO_BESTTIMES_LIST)
{
string packetStr = Encoding.UTF8.GetString(packet);
string gameName = packetStr.Substring(2, packetStr.Length - 4);
byte[] metaTag = PacketBuilder.CreateMetaPacket(Meta.BuildTopTimes(gameName));
sender.SendPacket(metaTag);
}
} }
public static void OnMovementPacket(GameClient sender, byte[] packet) public static void OnMovementPacket(GameClient sender, byte[] packet)
@ -1728,7 +1746,7 @@ namespace HISP.Server
byte[] loginMessageBytes = PacketBuilder.CreateChat(Messages.FormatLoginMessage(sender.LoggedinUser.Username), PacketBuilder.CHAT_BOTTOM_LEFT); byte[] loginMessageBytes = PacketBuilder.CreateChat(Messages.FormatLoginMessage(sender.LoggedinUser.Username), PacketBuilder.CHAT_BOTTOM_LEFT);
foreach (GameClient client in ConnectedClients) foreach (GameClient client in ConnectedClients)
if (client.LoggedIn) if (client.LoggedIn)
if (!client.LoggedinUser.MuteLogins || client.LoggedinUser.MuteAll) if (!client.LoggedinUser.MuteLogins && !client.LoggedinUser.MuteAll)
if (client.LoggedinUser.Id != userId) if (client.LoggedinUser.Id != userId)
client.SendPacket(loginMessageBytes); client.SendPacket(loginMessageBytes);
@ -1747,7 +1765,6 @@ namespace HISP.Server
public static void OnDisconnect(GameClient sender) public static void OnDisconnect(GameClient sender)
{ {
connectedClients.Remove(sender); connectedClients.Remove(sender);
Logger.DebugPrint("owoo disconnect");
if (sender.LoggedIn) if (sender.LoggedIn)
{ {
Database.RemoveOnlineUser(sender.LoggedinUser.Id); Database.RemoveOnlineUser(sender.LoggedinUser.Id);
@ -1755,7 +1772,7 @@ namespace HISP.Server
byte[] logoutMessageBytes = PacketBuilder.CreateChat(Messages.FormatLogoutMessage(sender.LoggedinUser.Username), PacketBuilder.CHAT_BOTTOM_LEFT); byte[] logoutMessageBytes = PacketBuilder.CreateChat(Messages.FormatLogoutMessage(sender.LoggedinUser.Username), PacketBuilder.CHAT_BOTTOM_LEFT);
foreach (GameClient client in ConnectedClients) foreach (GameClient client in ConnectedClients)
if (client.LoggedIn) if (client.LoggedIn)
if (!client.LoggedinUser.MuteLogins) if (!client.LoggedinUser.MuteLogins && !client.LoggedinUser.MuteAll)
if (client.LoggedinUser.Id != sender.LoggedinUser.Id) if (client.LoggedinUser.Id != sender.LoggedinUser.Id)
client.SendPacket(logoutMessageBytes); client.SendPacket(logoutMessageBytes);
// Tell clients of diconnect (remove from chat) // Tell clients of diconnect (remove from chat)

View file

@ -40,18 +40,22 @@ namespace HISP.Server
public const byte PACKET_PLAYERINFO = 0x16; public const byte PACKET_PLAYERINFO = 0x16;
public const byte PACKET_INFORMATION = 0x28; public const byte PACKET_INFORMATION = 0x28;
public const byte SECCODE_QUEST = 0x32; public const byte SECCODE_QUEST = 0x32;
public const byte SECCODE_ITEM = 0x28; public const byte SECCODE_ITEM = 0x28;
public const byte SECCODE_SCORE = 0x3D; public const byte SECCODE_SCORE = 0x3D;
public const byte SECCODE_TIME = 0x3E; public const byte SECCODE_TIME = 0x3E;
public const byte SECCODE_MONEY = 0x1E; public const byte SECCODE_MONEY = 0x1E;
public const byte NPC_START_CHAT = 0x14; public const byte NPC_START_CHAT = 0x14;
public const byte NPC_CONTINUE_CHAT = 0x15; public const byte NPC_CONTINUE_CHAT = 0x15;
public const byte PLAYERINFO_LEAVE = 0x16; public const byte PLAYERINFO_LEAVE = 0x16;
public const byte PLAYERINFO_UPDATE_OR_CREATE = 0x15; public const byte PLAYERINFO_UPDATE_OR_CREATE = 0x15;
public const byte PLAYERINFO_HIGHSCORES_LIST = 0x51;
public const byte PLAYERINFO_BESTTIMES_LIST = 0x52;
public const byte VIEW_PROFILE = 0x14; public const byte VIEW_PROFILE = 0x14;
public const byte SAVE_PROFILE = 0x15; public const byte SAVE_PROFILE = 0x15;