public static async Task Percent(CommandContext bc) { // get rsn var rsn = await bc.GetPlayerName(bc.MessageTokens.Length > 1 ? bc.MessageTokens.Join(1) : bc.From.Nickname); var p = await Player.FromHiscores(rsn); if (!p.Ranked) { await bc.SendReply(@"\b{0}\b doesn't feature Hiscores.", rsn); return; } long totalExp = p.Skills[Skill.OVER].Exp; long combatExp = p.Skills[Skill.COMB].Exp; long f2pExp = p.Skills.F2pExp; // slayer long hits_exp_gained = p.Skills[Skill.HITP].Exp - 1154; var expected_max_slayer_exp = (int) (hits_exp_gained * 3.0 / 4.0); // pc long expected_combat_xp = p.Skills[Skill.HITP].Exp + p.Skills[Skill.HITP].Exp * 12 / 4; long current_combat_xp = p.Skills[Skill.HITP].Exp + p.Skills[Skill.ATTA].Exp + p.Skills[Skill.STRE].Exp + p.Skills[Skill.DEFE].Exp + p.Skills[Skill.RANG].Exp; await bc.SendReply(@"\b{0}\b statistic percentages | Total exp: \c07{1:N0}\c | Combat exp: \c07{2:N0}\c (\c07{3:0.##}%\c) | F2P exp: \c07{4:N0}\c (\c07{5:0.##}%\c) | Slayer%: \c07{6:0.##}% - {7:0.##}%\c | PestControl%: \c07{8:0.##}%\c", rsn, totalExp, combatExp, (double) combatExp / totalExp * 100, f2pExp, (double) f2pExp / totalExp * 100, (double) p.Skills[Skill.SLAY].Exp / expected_max_slayer_exp * 100, (double) p.Skills[Skill.SLAY].Exp / (expected_max_slayer_exp - (hits_exp_gained / 133)) * 100, (double) (current_combat_xp - expected_combat_xp) / current_combat_xp * 100); }
public static async Task Start(CommandContext bc) { // get rsn string rsn = await bc.GetPlayerName(bc.From.Nickname); var p = await Player.FromHiscores(rsn); if (!p.Ranked) { await bc.SendReply(@"\b{0}\b doesn't feature Hiscores.", rsn); return; } // get timer name string name = string.Empty; int indexOfSharp = bc.Message.IndexOf('#'); if (indexOfSharp > 0) { name = bc.Message.Substring(indexOfSharp + 1); bc.Message = bc.Message.Substring(0, indexOfSharp - 1); } // get skill string skill = Skill.OVER; if (bc.MessageTokens.Length > 1) { Skill.TryParse(bc.MessageTokens[1], ref skill); } // remove previous timer with this name, if any await Database.ExecuteNonQuery("DELETE FROM timers_exp WHERE fingerprint='" + bc.From.FingerPrint + "' AND name='" + name.Replace("'", "''") + "'"); // start a new timer with this name await Database.Insert("timers_exp", "fingerprint", bc.From.FingerPrint, "name", name, "skill", skill, "exp", p.Skills[skill].Exp.ToStringI(), "datetime", DateTime.UtcNow.ToStringI("yyyyMMddHHmmss")); await bc.SendReply(@"\b{0}\b starting exp of \c07{1:e}\c in \u{1:n}\u has been recorded{2}.", rsn, p.Skills[skill], name.Length > 0 ? @" on timer \c07" + name + @"\c" : string.Empty); }
public static async Task Graph(CommandContext bc) { string skill = Skill.OVER; string rsn = await bc.GetPlayerName(bc.From.Nickname); if (bc.MessageTokens.Length > 1) { if (Skill.TryParse(bc.MessageTokens[1], ref skill)) { if (bc.MessageTokens.Length > 2) { rsn = await bc.GetPlayerName(bc.MessageTokens.Join(2)); } } else { rsn = await bc.GetPlayerName(bc.MessageTokens.Join(1)); } } await bc.SendReply(@"\b{0}\b \c07{1}\c graph | level: \c12http://t.rscript.org/graph-{0}.{2}.lvl.png\c | exp: \c12http://t.rscript.org/graph-{0}.{2}.png\c | rank: \c12http://t.rscript.org/graph-{0}.{2}.rank.png\c", rsn, skill.ToLowerInvariant(), Skill.NameToId(skill)); }
public static async Task F2pPercent(CommandContext bc) { // get rsn string rsn; if (bc.MessageTokens.Length > 1) { rsn = await bc.GetPlayerName(bc.MessageTokens.Join(1)); } else { rsn = await bc.GetPlayerName(bc.From.Nickname); } var p = await Player.FromHiscores(rsn); if (!p.Ranked) { await bc.SendReply(@"\b{0}\b doesn't feature Hiscores.", rsn); return; } await bc.SendReply(@"\b{0}\b is \c07{1:0.##}%\c f2p based, with \c07{2:N0}\c f2p based exp. and \c07{3:e}\c total exp.", rsn, (double) p.Skills.F2pExp / (double) p.Skills[Skill.OVER].Exp * 100, p.Skills.F2pExp, p.Skills[Skill.OVER]); }
public static async Task Check(CommandContext bc) { // get rsn string rsn = await bc.GetPlayerName(bc.From.Nickname); var p = await Player.FromHiscores(rsn); if (!p.Ranked) { await bc.SendReply(@"\b{0}\b doesn't feature Hiscores.", rsn); return; } // get timer name string name = string.Empty; int indexofsharp = bc.Message.IndexOf('#'); if (indexofsharp > 0) { name = bc.Message.Substring(indexofsharp + 1); bc.Message = bc.Message.Substring(0, indexofsharp - 1); } var rs = await Database.FetchFirst("SELECT skill,exp,datetime FROM timers_exp WHERE fingerprint=@fingerprint AND name=@name LIMIT 1", new MySqlParameter("@fingerprint", bc.From.FingerPrint), new MySqlParameter("@name", name)); if (rs != null) { string skill = rs.GetString(0); long gained_exp = p.Skills[skill].Exp - (uint) rs["exp"]; TimeSpan time = DateTime.UtcNow - rs.GetString(2).ToDateTime(); var reply = @"You gained \c07{0:N0}\c \u{1}\u exp in \c07{2}\c. That's \c07{3:N0}\c exp/h.".FormatWith(gained_exp, skill.ToLowerInvariant(), time.ToLongString(), (double) gained_exp / time.TotalHours); if (gained_exp > 0 && skill != Skill.OVER && skill != Skill.COMB && p.Skills[skill].VLevel < 126) { reply += @" Estimated time to level up: \c07{0}\c".FormatWith(TimeSpan.FromSeconds(p.Skills[skill].ExpToVLevel * time.TotalSeconds / gained_exp).ToLongString()); } await bc.SendReply(reply); } else { if (name.Length > 0) { await bc.SendReply("You must start timing a skill on that timer first."); } else { await bc.SendReply("You must start timing a skill first."); } } }
public static async Task Alog(CommandContext bc) { int timeSpan = 0; string timeSpanName = string.Empty; Match timeInterval = Regex.Match(bc.Message, @"@(.+?)( |$)"); if (timeInterval.Success) { var timePeriod = new TimeInterval(); if (timePeriod.Parse(timeInterval.Groups[1].Value)) { timeSpan = (int) timePeriod.Time.TotalSeconds; timeSpanName = timePeriod.Name; } else if (timeInterval.Groups[1].Value == "all") { timeSpan = int.MaxValue; } bc.Message = Regex.Replace(bc.Message, @"@(.+?)( |$)", string.Empty, RegexOptions.IgnoreCase); bc.Message = bc.Message.Trim(); } var rsn = await bc.GetPlayerName(bc.From.Nickname); if (bc.MessageTokens.GetLength(0) > 1) { rsn = await bc.GetPlayerName(bc.MessageTokens.Join(1)); } List<RssItem> list = null; try { var reader = new RssManager("http://services.runescape.com/m=adventurers-log/rssfeed?searchName=" + rsn); reader.GetFeed(); list = reader.RssItems; } catch { } if (list == null) { await bc.SendReply(@"No achievements found for \c7{0}\c{1}. The profile may be private, the player may be f2p, or the rsn incorrect.", rsn, string.IsNullOrEmpty(timeSpanName) ? string.Empty : @" in " + timeSpanName); return; } var p = await Player.FromHiscores(rsn); list.Sort((i1, i2) => i2.Date.CompareTo(i1.Date)); if (timeSpan > 0) { list.RemoveAll(i => (DateTime.UtcNow - i.Date).TotalSeconds > timeSpan); } else if (list.Count > 15) { list.RemoveAll(i => i.Date < list[14].Date); timeSpanName = "recent"; } if (list.Count == 0 || !p.Ranked) { await bc.SendReply(@"No achievements found for \c7{0}\c{1}. The profile may be private, the player may be f2p, or the rsn incorrect.", rsn, string.IsNullOrEmpty(timeSpanName) ? string.Empty : @" in " + timeSpanName); return; } const string questRegex = @"Quest complete: (.+)"; const string killRegex = @"killed the player (.+?)\.|I killed\s*(?:an?|the)?\s*(.+?)\.?$"; const string levelRegex = @"Level?led up (\w+)\.?|Levelled all skills over (\d+)"; const string itemRegex = @"Item found: (?:an?|some) (.+)"; const string expRegex = @"(\d+)XP in (\w+)"; const string duRegex = @"Dungeon level (\d+) reached."; var alogItems = new Dictionary<string, Dictionary<string, AlogItem>> { { "I reached", new Dictionary<string, AlogItem>() }, { "I gained", new Dictionary<string, AlogItem>() }, { "I killed", new Dictionary<string, AlogItem>() }, { "I found", new Dictionary<string, AlogItem>() }, { "I completed", new Dictionary<string, AlogItem>() }, { "Others", new Dictionary<string, AlogItem>() } }; foreach (RssItem item in list) { Match M = Regex.Match(item.Title, questRegex); if (M.Success) { var quest = new AlogItem(item, M, "I completed"); alogItems["I completed"].Add(alogItems["I completed"].Count.ToStringI(), quest); continue; } M = Regex.Match(item.Title, killRegex); if (M.Success) { var kill = new AlogItem(item, M, "I killed"); string npc = Regex.Replace(kill.Info[0].Replace("monsters", "monster"), @"\W", " "); if (alogItems["I killed"].ContainsKey(npc)) { alogItems["I killed"][npc].Amount += kill.Amount; } else { kill.Info[0] = npc; alogItems["I killed"].Add(npc, kill); } continue; } M = Regex.Match(item.Title, levelRegex); if (M.Success) { var level = new AlogItem(item, M, "I gained"); try { level.Info[0] = Skill.Parse(level.Info[0]); if (alogItems["I gained"].ContainsKey(level.Info[0])) { alogItems["I gained"][level.Info[0]].Amount++; } else { alogItems["I gained"].Add(level.Info[0], level); alogItems["I gained"][level.Info[0]].Info[1] = p.Skills[level.Info[0]].Level.ToStringI(); } } catch { if (alogItems["I gained"].ContainsKey("all")) { if (level.Info[1].ToInt32() > alogItems["I gained"]["all"].Info[1].ToInt32()) { alogItems["I gained"]["all"].Info[0] = "all"; alogItems["I gained"]["all"].Info[1] = level.Info[1]; } } else { alogItems["I gained"].Add("all", level); alogItems["I gained"]["all"].Info[0] = "all"; } } continue; } M = Regex.Match(item.Title, itemRegex); if (M.Success) { var drop = new AlogItem(item, M, "I found"); if (alogItems["I found"].ContainsKey(drop.Info[0])) { alogItems["I found"][drop.Info[0]].Amount++; } else { alogItems["I found"].Add(drop.Info[0], drop); } continue; } M = Regex.Match(item.Title, duRegex); if (M.Success) { var duFloor = new AlogItem(item, M, "Others"); if (!alogItems["Others"].ContainsKey("duFloor")) { alogItems["Others"].Add("duFloor", duFloor); alogItems["Others"]["duFloor"].Info[1] = "1"; } alogItems["Others"]["duFloor"].Info[0] = "duFloor"; if (M.Groups[1].Value.ToInt32() > alogItems["Others"]["duFloor"].Info[1].ToInt32()) { alogItems["Others"]["duFloor"].Info[1] = M.Groups[1].Value; } continue; } M = Regex.Match(item.Title, expRegex); if (M.Success) { var exp = new AlogItem(item, M, "I reached"); if (alogItems["I reached"].ContainsKey(exp.Info[1])) { if (alogItems["I reached"][exp.Info[1]].Info[0].ToInt32() < exp.Info[0].ToInt32()) { alogItems["I reached"].Remove(exp.Info[1]); alogItems["I reached"].Add(exp.Info[1], exp); } } else { alogItems["I reached"].Add(exp.Info[1], exp); } continue; } var other = new AlogItem(item, null, "Others"); alogItems["Others"].Add(alogItems["Others"].Count.ToStringI(), other); } string reply = rsn + "'s achievements" + (string.IsNullOrEmpty(timeSpanName) ? string.Empty : " (" + timeSpanName + ")") + ": "; foreach (var category in alogItems) { if (category.Value.Count == 0) { continue; } reply += category.Key + ": "; foreach (AlogItem item in category.Value.Values) { string amount = string.Empty; if (item.Amount > 1) { amount = @"\c07{0}\cx ".FormatWith(item.Amount); } if (category.Key == "I reached") { var skill = new Skill(item.Info[1], 1, 1); reply += @"\c07{0}\c {1} exp; ".FormatWith(item.Info[0].ToInt32().ToShortString(1), skill.ShortName); } else if (category.Key == "I gained") { if (item.Info[0] == "all") { reply += @"All skills now at least \c07{0}\c; ".FormatWith(item.Info[1]); } else { var skill = new Skill(item.Info[0], 1, 1); reply += @"\c07{0}\c {1} levels(->{2}); ".FormatWith(item.Amount, skill.ShortName, item.Info[1]); } } else if (item.Info[0] == "duFloor") { reply += @"Unlocked dungeon floor \c07{0}\c; ".FormatWith(item.Info[1]); } else { reply += amount + @"\c07{0}\c; ".FormatWith(item.Info[0]); } } } await bc.SendReply(reply.Trim()); }
public static async Task Track(CommandContext bc) { // get time int intervalTime = 604800; string intervalName = "1 week"; Match interval = Regex.Match(bc.Message, @"@(\d+)?(second|minute|month|hour|week|year|sec|min|day|s|m|h|d|w|y)s?", RegexOptions.IgnoreCase); if (interval.Success) { if (interval.Groups[1].Value.Length > 0) { intervalTime = int.Parse(interval.Groups[1].Value, CultureInfo.InvariantCulture); } else { intervalTime = 1; } if (intervalTime < 1) { intervalTime = 1; } switch (interval.Groups[2].Value) { case "second": case "sec": case "s": intervalName = intervalTime + " second" + (intervalTime == 1 ? string.Empty : "s"); break; case "minute": case "min": case "m": intervalName = intervalTime + " minute" + (intervalTime == 1 ? string.Empty : "s"); intervalTime *= 60; break; case "hour": case "h": intervalName = intervalTime + " hour" + (intervalTime == 1 ? string.Empty : "s"); intervalTime *= 3600; break; case "day": case "d": intervalName = intervalTime + " day" + (intervalTime == 1 ? string.Empty : "s"); intervalTime *= 86400; break; case "week": case "w": intervalName = intervalTime + " week" + (intervalTime == 1 ? string.Empty : "s"); intervalTime *= 604800; break; case "month": intervalName = intervalTime + " month" + (intervalTime == 1 ? string.Empty : "s"); intervalTime *= 2629746; break; case "year": case "y": intervalName = intervalTime + " year" + (intervalTime == 1 ? string.Empty : "s"); intervalTime *= 31556952; break; } bc.Message = Regex.Replace(bc.Message, @"@(\d+)?(second|minute|month|hour|week|year|sec|min|day|s|m|h|d|w|y)s?", string.Empty, RegexOptions.IgnoreCase); bc.Message = bc.Message.Trim(); } intervalName = "last " + intervalName; // get rsn string rsn; if (bc.MessageTokens.Length > 1) { rsn = await bc.GetPlayerName(bc.MessageTokens.Join(1)); } else { rsn = await bc.GetPlayerName(bc.From.Nickname); } // Get new player var PlayerNew = await Player.FromHiscores(rsn); if (!PlayerNew.Ranked) { await bc.SendReply(@"\b{0}\b doesn't feature Hiscores.", rsn); return; } // Get old player var PlayerOld = new Player(rsn, intervalTime); if (!PlayerOld.Ranked) { await bc.SendReply(@"\b{0}\b wasn't being tracked on {1}.", rsn, DateTime.UtcNow.AddSeconds(-intervalTime).ToStringI("yyyy-MMM-dd")); return; } // 1st line: overall / combat string ReplyMsg = @"\b{0}\b \u{1}\u skills:".FormatWith(rsn, intervalName); Skill OverallDif = PlayerNew.Skills[Skill.OVER] - PlayerOld.Skills[Skill.OVER]; if (OverallDif.Exp <= 0) { await bc.SendReply(@"No performance for \b{0}\b within this period.", rsn); } else { Skill CombatDif = PlayerNew.Skills[Skill.COMB] - PlayerOld.Skills[Skill.COMB]; string DifLevel = string.Empty; if (OverallDif.Level > 0) { DifLevel = @" [\b+{0}\b]".FormatWith(OverallDif.Level); } ReplyMsg += @" \c07Overall\c lvl {0} \c3+{1}\c xp (Avg. hourly exp.: \c07{2}\c)".FormatWith(PlayerNew.Skills[Skill.OVER].Level + DifLevel, OverallDif.Exp.ToShortString(1), (OverallDif.Exp / (intervalTime / 3600.0)).ToShortString(0)); DifLevel = string.Empty; if (CombatDif.Level > 0) { DifLevel = @" [\b+{0}\b]".FormatWith(CombatDif.Level); } ReplyMsg += @"; \c7Combat\c lvl {0} \c03+{1}\c xp (\c07{2}%\c)".FormatWith(PlayerNew.Skills[Skill.COMB].Level + DifLevel, CombatDif.Exp.ToShortString(1), (CombatDif.Exp / (double) OverallDif.Exp * 100.0).ToShortString(1)); await bc.SendReply(ReplyMsg); // 2nd line: skills list List<Skill> SkillsDif = (from SkillNow in PlayerNew.Skills.Values where SkillNow.Name != Skill.OVER && SkillNow.Name != Skill.COMB select SkillNow - PlayerOld.Skills[SkillNow.Name]).ToList(); SkillsDif.Sort(); ReplyMsg = @"\b{0}\b \u{1}\u skills:".FormatWith(rsn, intervalName); for (int i = 0; i < 10; i++) { if (SkillsDif[i].Exp > 0) { DifLevel = string.Empty; if (SkillsDif[i].Level > 0) { DifLevel = @" [\b+{0}\b]".FormatWith(SkillsDif[i].Level); } ReplyMsg += @" \c07{0}\c lvl {1} \c3+{2}\c xp;".FormatWith(SkillsDif[i].Name, PlayerNew.Skills[SkillsDif[i].Name].Level + DifLevel, SkillsDif[i].Exp.ToShortString(1)); } } await bc.SendReply(ReplyMsg); } }
public static async Task ClanPerformance(CommandContext bc) { string clanInitials; string clanName; if (bc.Message.ContainsI("SS")) { clanInitials = "SS"; clanName = "Supreme Skillers"; } else if (bc.Message.ContainsI("TS")) { clanInitials = "TS"; clanName = "True Skillers"; } else { clanInitials = "PT"; clanName = "Portugal"; } var rsn = await bc.GetPlayerName(bc.From.Nickname); string skill = null; int rank = 0; bool IsIndividual = false; // get last updated player date DateTime lastUpdate = (await Database.Lookup<string>("lastUpdate", "players", "ORDER BY lastUpdate DESC")).ToDateTime(); DateTime firstDay, lastDay; if (bc.MessageTokens[0].Contains("yesterday") || bc.MessageTokens[0].Contains("yday")) { lastDay = lastUpdate; firstDay = lastDay.AddDays(-1); } else if (bc.MessageTokens[0].Contains("lastweek") | bc.MessageTokens[0].Contains("lweek")) { lastDay = lastUpdate.AddDays(-((int) lastUpdate.DayOfWeek)); firstDay = lastDay.AddDays(-7); } else if (bc.MessageTokens[0].Contains("lastmonth") | bc.MessageTokens[0].Contains("lmonth")) { lastDay = lastUpdate.AddDays(1 - lastUpdate.Day); firstDay = lastDay.AddMonths(-1); } else if (bc.MessageTokens[0].Contains("lastyear") | bc.MessageTokens[0].Contains("lyear")) { lastDay = lastUpdate.AddDays(1 - lastUpdate.DayOfYear); firstDay = lastDay.AddYears(-1); } else if (bc.MessageTokens[0].Contains("week")) { firstDay = lastUpdate.AddDays(-((int) lastUpdate.DayOfWeek)); lastDay = lastUpdate; } else if (bc.MessageTokens[0].Contains("month")) { firstDay = lastUpdate.AddDays(1 - lastUpdate.Day); lastDay = lastUpdate; } else if (bc.MessageTokens[0].Contains("year")) { firstDay = lastUpdate.AddDays(1 - lastUpdate.DayOfYear); lastDay = lastUpdate; } else { Match M = Regex.Match(bc.MessageTokens[0], "last(\\d+)days"); if (M.Success) { lastDay = lastUpdate; firstDay = lastDay.AddDays(-int.Parse(M.Groups[1].Value, CultureInfo.InvariantCulture)); } else { return; } } if (firstDay == lastDay) { return; } // Create a list of Clan players var clanPlayers = await Players.FromClanAsPeriod(clanInitials, firstDay, lastDay); // Parse command arguments if (bc.MessageTokens.Length == 1) { // !ClanTop IsIndividual = true; } else if (Skill.TryParse(bc.MessageTokens[1], ref skill)) { // !ClanTop Skill rank = 1; // Clean and sort clan members by specified skill clanPlayers = clanPlayers.Where(p => p.Skills[skill].Exp > 0) .OrderByDescending(p => p.Skills[skill].Exp) .ToList(); if (bc.MessageTokens.Length > 2) { if (int.TryParse(bc.MessageTokens[2], out rank)) { // !ClanTop Skill Rank } else if (bc.MessageTokens.Length == 3 && bc.MessageTokens[2].ToUpperInvariant() == "@LAST") { // !ClanTop Skill @last rank = clanPlayers.Count; } else { // !ClanTop Skill rsn = await bc.GetPlayerName(bc.MessageTokens.Join(1)); var indexOfPlayer = clanPlayers.FindIndex(p => p.Name.EqualsI(rsn)); if (indexOfPlayer != -1) { rank = indexOfPlayer + 1; } } } } else { // !ClanTop RSN rsn = await bc.GetPlayerName(bc.MessageTokens.Join(1)); IsIndividual = true; } if (IsIndividual) { var player = clanPlayers.FirstOrDefault(p => p.Name.EqualsI(rsn)); if (player != null) { // individual skill ranks var reply = @"[{0}] \b{1}\b skill ranks:"; foreach (var s in player.Skills.Values.Where(s => s.Exp > 0)) { var indexOfPlayer = clanPlayers.OrderBy(p => p.Skills[s.Name]).IndexOf(player); reply += @" \c07#{0}\c {1};".FormatWith(indexOfPlayer + 1, s.ShortName); } await bc.SendReply(reply, clanInitials, rsn); } else { await bc.SendReply(@"\b{0}\b wasn't at {1}.", rsn, clanName); } return; } // Get input player rank var inputPlayerName = await bc.GetPlayerName(bc.From.Nickname); var inputPlayerRank = clanPlayers.FindIndex(p => p.Name.EqualsI(inputPlayerName)) + 1; // fix rank if (rank < 1) { rank = 1; } else if (rank > clanPlayers.Count) { rank = clanPlayers.Count; } int MinRank = rank - 6; if (MinRank < 0) { MinRank = 0; } else if (MinRank > clanPlayers.Count - 11) { MinRank = clanPlayers.Count - 11; } if (clanPlayers.Count > 0) { string reply = @"[{0}] \u{1}\u ranking:".FormatWith(clanInitials, skill.ToLowerInvariant()); if (inputPlayerRank > 0 && inputPlayerRank <= MinRank) { reply += @" \c7#{0}\c \u{1}\u ({2:e});".FormatWith(inputPlayerRank, clanPlayers[inputPlayerRank - 1].Name, clanPlayers[inputPlayerRank - 1].Skills[skill]); } for (int i = MinRank; i < Math.Min(MinRank + 11, clanPlayers.Count); i++) { reply += " "; if (i == rank - 1) { reply += @"\b"; } reply += @"\c07#{0}\c ".FormatWith(i + 1); if (i == inputPlayerRank - 1) { reply += @"\u"; } reply += clanPlayers[i].Name; if (i == inputPlayerRank - 1) { reply += @"\u"; } reply += " (" + clanPlayers[i].Skills[skill].ToStringI("e") + ")"; if (i == rank - 1) { reply += @"\b"; } reply += ";"; } if (inputPlayerRank > 0 && inputPlayerRank > MinRank + 11) { reply += @" \c7#{0}\c \u{1}\u ({2:e});".FormatWith(inputPlayerRank, clanPlayers[inputPlayerRank - 1].Name, clanPlayers[inputPlayerRank - 1].Skills[skill]); } await bc.SendReply(reply); } else { await bc.SendReply(clanName + " didn't have any member ranked at this skill."); } }
public static async Task Activity(CommandContext bc) { // get player var player = await Player.FromHiscores(await bc.GetPlayerName(bc.MessageTokens.Length > 1 ? bc.MessageTokens.Join(1) : bc.From.Nickname)); if (player.Ranked) { Activity activity = player.Activities[Bot.Activity.Parse(bc.MessageTokens[0])]; if (activity.Rank > 0) { string reply = @"\b{0}\b \c07{1:n}\c | score: \c07{1:s}\c | rank: \c07{1:R}\c".FormatWith(player.Name, activity); // Add SS rank if applicable var ssPlayers = (await Players.FromClan("SS")).OrderBy(p => p.Activities[activity.Name]); var ssRank = ssPlayers.FindIndex(p => p.Name.EqualsI(player.Name)); if (ssRank != -1) { reply += @" (SS rank: \c07{0}\c)".FormatWith(ssRank + 1); } await bc.SendReply(reply); // Show player performance if applicable var dblastupdate = await Database.LastUpdate(player.Name); if (dblastupdate != null && dblastupdate.Length == 8) { DateTime lastupdate = dblastupdate.ToDateTime(); string perf; reply = string.Empty; var p_old = await Player.FromDatabase(player.Name, lastupdate); if (p_old.Ranked) { perf = _GetPerformance("Today", p_old.Activities[activity.Name], activity); if (perf != null) { reply += perf + " | "; } } p_old = await Player.FromDatabase(player.Name, lastupdate.AddDays(-((int) lastupdate.DayOfWeek))); if (p_old.Ranked) { perf = _GetPerformance("Week", p_old.Activities[activity.Name], activity); if (perf != null) { reply += perf + " | "; } } p_old = await Player.FromDatabase(player.Name, lastupdate.AddDays(1 - lastupdate.Day)); if (p_old.Ranked) { perf = _GetPerformance("Month", p_old.Activities[activity.Name], activity); if (perf != null) { reply += perf + " | "; } } p_old = await Player.FromDatabase(player.Name, lastupdate.AddDays(1 - lastupdate.DayOfYear)); if (p_old.Ranked) { perf = _GetPerformance("Year", p_old.Activities[activity.Name], activity); if (perf != null) { reply += perf; } } if (reply.Length > 0) { await bc.SendReply(reply.EndsWithI(" | ") ? reply.Substring(0, reply.Length - 3) : reply); } } return; } } await bc.SendReply(@"\b{0}\b doesn't feature Hiscores.", player.Name); }
public static async Task ClanTop(CommandContext bc) { string clanInitials; string clanName; if (bc.Message.ContainsI("SS")) { clanInitials = "SS"; clanName = "Supreme Skillers"; } else if (bc.Message.ContainsI("TS")) { clanInitials = "TS"; clanName = "True Skillers"; } else { clanInitials = "PT"; clanName = "Portugal"; } var rsn = await bc.GetPlayerName(bc.From.Nickname); string skill = null, activity = null; int rank = 0; bool IsIndividual = false; // get @exp bool exp = false; if (bc.Message.Contains(" @exp") || bc.Message.Contains(" @xp")) { exp = true; bc.Message = bc.Message.Replace(" @exp", string.Empty); bc.Message = bc.Message.Replace(" @xp", string.Empty); } // Create a list of Clan players var clanPlayers = await Players.FromClan(clanInitials); // Parse command arguments if (bc.MessageTokens.Length == 1) { // !ClanTop IsIndividual = true; } else if (Bot.Activity.TryParse(bc.MessageTokens[1], ref activity) || Skill.TryParse(bc.MessageTokens[1], ref skill)) { // !ClanTop Skill/Activity rank = 1; // Clean and sort clan members by specified skill if (activity == null) { var players = clanPlayers.Where(p => p.Skills[skill].Exp > 0); players = exp ? players.OrderByDescending(p => p.Skills[skill].Exp).ThenBy(p => p.Skills[skill].Rank) : players.OrderBy(p => p.Skills[skill]); clanPlayers = players.ToList(); } else { clanPlayers = clanPlayers.Where(p => p.Activities[activity].Score > 0).OrderBy(p => p.Activities[activity]).ToList(); } if (bc.MessageTokens.Length > 2) { if (int.TryParse(bc.MessageTokens[2], out rank)) { // !ClanTop Skill/Activity Rank } else if (bc.MessageTokens.Length == 3 && bc.MessageTokens[2].ToUpperInvariant() == "@LAST") { // !ClanTop Skill/Activity @last rank = clanPlayers.Count; } else { // !ClanTop Skill/Activity RSN rsn = await bc.GetPlayerName(bc.MessageTokens.Join(2)); var indexOfPlayer = clanPlayers.FindIndex(p => p.Name.EqualsI(rsn)); if (indexOfPlayer != -1) { rank = indexOfPlayer + 1; } } } } else { // !ClanTop RSN rsn = await bc.GetPlayerName(bc.MessageTokens.Join(1)); IsIndividual = true; } if (IsIndividual) { var player = clanPlayers.FirstOrDefault(p => p.Name.EqualsI(rsn)); if (player != null) { // individual skill ranks string reply = @"[{0}] \b{1}\b skill ranks:".FormatWith(clanInitials, rsn); foreach (var s in player.Skills.Values.Where(s => s.Exp > 0)) { var indexOfPlayer = clanPlayers.OrderBy(p => p.Skills[s.Name]).IndexOf(player); reply += @" \c7#{0}\c {1};".FormatWith(indexOfPlayer + 1, s.ShortName); } await bc.SendReply(reply); // individual activity ranks bool ranked = false; reply = @"[{0}] \b{1}\b activity ranks:".FormatWith(clanInitials, rsn); foreach (var a in player.Activities.Values.Where(a => a.Score > 0)) { ranked = true; var indexOfPlayer = clanPlayers.OrderBy(p => p.Activities[a.Name]).IndexOf(player); reply += @" \c7#{0}\c {1};".FormatWith(indexOfPlayer + 1, a.Name); } if (ranked) { await bc.SendReply(reply); } } else { await bc.SendReply(@"\b{0}\b isn't at {1}.", rsn, clanName); } return; } // Get input player rank var inputPlayerName = await bc.GetPlayerName(bc.From.Nickname); var inputPlayerRank = clanPlayers.FindIndex(p => p.Name.EqualsI(inputPlayerName)) + 1; // fix rank if (rank < 1) { rank = 1; } else if (rank > clanPlayers.Count) { rank = clanPlayers.Count; } int MinRank = rank - 6; if (MinRank < 0) { MinRank = 0; } else if (MinRank > clanPlayers.Count - 11) { MinRank = clanPlayers.Count - 11; } var skillFormat = exp ? "e" : "l"; if (activity == null) { if (clanPlayers.Count > 0) { var reply = @"[{0}] \u{1}\u ranking:".FormatWith(clanInitials, skill.ToLowerInvariant()); if (inputPlayerRank > 0 && inputPlayerRank <= MinRank) { reply += @" \c7#{0}\c \u{1}\u ({2});".FormatWith(inputPlayerRank, clanPlayers[inputPlayerRank - 1].Name, clanPlayers[inputPlayerRank - 1].Skills[skill].ToStringI(skillFormat)); } for (int i = MinRank; i < Math.Min(MinRank + 11, clanPlayers.Count); i++) { reply += " "; if (i == rank - 1) { reply += @"\b"; } reply += @"\c7#{0}\c ".FormatWith(i + 1); if (i == inputPlayerRank - 1) { reply += @"\u"; } reply += clanPlayers[i].Name; if (i == inputPlayerRank - 1) { reply += @"\u"; } reply += " (" + clanPlayers[i].Skills[skill].ToStringI(skillFormat) + ")"; if (i == rank - 1) { reply += @"\b"; } reply += ";"; } if (inputPlayerRank > 0 && inputPlayerRank > MinRank + 11) { reply += @" \c7#{0}\c \u{1}\u ({2:e});".FormatWith(inputPlayerRank, clanPlayers[inputPlayerRank - 1].Name, clanPlayers[inputPlayerRank - 1].Skills[skill].ToStringI(skillFormat)); } await bc.SendReply(reply); } else { await bc.SendReply(clanName + " don't have any member ranked at this skill."); } } else { if (clanPlayers.Count > 0) { var reply = @"[{0}] \u{1}\u ranking:".FormatWith(clanInitials, activity.ToLowerInvariant()); if (inputPlayerRank > 0 && inputPlayerRank <= MinRank) { reply += @" \c7#{0}\c \u{1}\u ({2});".FormatWith(inputPlayerRank, clanPlayers[inputPlayerRank - 1].Name, clanPlayers[inputPlayerRank - 1].Activities[activity].Score); } for (int i = MinRank; i < Math.Min(MinRank + 11, clanPlayers.Count); i++) { reply += " "; if (i == rank - 1) { reply += @"\b"; } reply += @"\c7#{0}\c ".FormatWith(i + 1); if (i == inputPlayerRank - 1) { reply += @"\u"; } reply += clanPlayers[i].Name; if (i == inputPlayerRank - 1) { reply += @"\u"; } reply += " (" + clanPlayers[i].Activities[activity].Score + ")"; if (i == rank - 1) { reply += @"\b"; } reply += ";"; } if (inputPlayerRank > 0 && inputPlayerRank > MinRank + 11) { reply += @" \c07#" + inputPlayerRank + @"\c \u" + clanPlayers[inputPlayerRank - 1].Name + @"\u (" + clanPlayers[inputPlayerRank - 1].Activities[activity].Score + ");"; } await bc.SendReply(reply); } else { await bc.SendReply(clanName + " don't have any member ranked at this activity."); } } }
private static async Task _SetGoal(CommandContext bc) { if (bc.MessageTokens.Length < 3) { await bc.SendReply("Syntax: !set goal <skill> [goal]"); return; } string skill = null; string goal = null; if (Skill.TryParse(bc.MessageTokens[2], ref skill)) { if (bc.MessageTokens.Length > 3) { // !set goal <skill> <goal> goal = bc.MessageTokens[3]; } // else { // !set goal <skill> } } else if (bc.MessageTokens.Length > 3 && Skill.TryParse(bc.MessageTokens[3], ref skill)) { // !set goal <goal> <skill> goal = bc.MessageTokens[2]; } else { await bc.SendReply("Error: Invalid skill name."); return; } if (goal == null) { // Get goal from database goal = await Database.GetStringParameter("users", "goals", "fingerprint='" + bc.From.FingerPrint + "'", skill, "nl"); } else if (!Regex.Match(goal, @"n(?:l|r)|r?\d+(?:\.\d+)?(?:m|k)?").Success) { await bc.SendReply("Error: Invalid goal."); return; } // Add this player to database if he never set a default name. if (await Database.Lookup<long>("COUNT(*)", "users", "fingerprint=@fp", new[] { new MySqlParameter("@fp", bc.From.FingerPrint) }) < 1) { await Database.Insert("users", "fingerprint", bc.From.FingerPrint, "rsn", await bc.GetPlayerName(bc.From.Nickname)); } if (goal.EqualsI("nl")) { await bc.SendReply(@"Your goal for \b{0}\b is currently set to \unext level\u.", skill); } else if (goal.EqualsI("nr")) { await bc.SendReply(@"Your goal for \b{0}\b is currently set to \unext rank\u.", skill); } else if (goal.StartsWithI("r")) { int goalRank = goal.Substring(1).ToInt32(); if (goalRank > 0 && goalRank <= 2000000) { await bc.SendReply(@"Your goal for \b{0}\b is currently set to \urank {1}\u.", skill, goalRank.ToShortString(1)); goal = "r" + goalRank.ToStringI(); } else { await bc.SendReply(@"Your goal for \b{0}\b is currently set to \unext rank\u.", skill); goal = "nr"; } } else { int goalLevel = goal.ToInt32(); if (goalLevel > 1 && goalLevel < 127) { await bc.SendReply(@"Your goal for \b{0}\b is currently set to \ulevel {1}\u.", skill, goalLevel); goal = goalLevel.ToStringI(); } else if (goalLevel == 127) { await bc.SendReply(@"Your goal for \b{0}\b is currently set to \u200m exp\u.", skill); goal = goalLevel.ToStringI(); } else if (goalLevel > 127 && goalLevel <= 200000000) { await bc.SendReply(@"Your goal for \b{0}\b is currently set to \u{1} exp\u.", skill, goalLevel.ToShortString(1)); goal = goalLevel.ToStringI(); } else { await bc.SendReply(@"Your goal for \b{0}\b is currently set to \unext level\u.", skill); goal = "nl"; } } await Database.SetStringParameter("users", "goals", "fingerprint='" + bc.From.FingerPrint + "'", skill, goal); }
private static async Task _SetSkill(CommandContext bc) { if (bc.MessageTokens.Length < 3) { await bc.SendReply("Syntax: !set skill <skill>"); return; } if (bc.MessageTokens[2].ToLowerInvariant() == "on" || bc.MessageTokens[2].ToLowerInvariant() == "off") { await _SetSkillToggle(bc); return; } string skill = Skill.OVER; if (!Skill.TryParse(bc.MessageTokens[2], ref skill)) { await bc.SendReply("Error: Invalid skill name."); return; } // Add this player to database if he never set a default name. if (await Database.Lookup<long>("COUNT(*)", "users", "fingerprint=@fp", new[] { new MySqlParameter("@fp", bc.From.FingerPrint) }) < 1) { await Database.Insert("users", "fingerprint", bc.From.FingerPrint, "rsn", await bc.GetPlayerName(bc.From.Nickname)); } await Database.Update("users", "fingerprint='" + bc.From.FingerPrint + "'", "skill", skill); await bc.SendReply(@"Your default skill is currently set to \b{0}\b.", skill); }
private static async Task _SetSkillToggle(CommandContext bc) { if (bc.MessageTokens.Length < 3 || (bc.MessageTokens[2].ToLowerInvariant() != "on" && bc.MessageTokens[2].ToLowerInvariant() != "off")) { await bc.SendReply("Syntax: !set @ <on|off>"); return; } string state = bc.MessageTokens[2].ToLowerInvariant(); // Add this player to database if he never set a default name. if (await Database.Lookup<long>("COUNT(*)", "users", "fingerprint=@fp", new[] { new MySqlParameter("@fp", bc.From.FingerPrint) }) < 1) { await Database.Insert("users", "fingerprint", bc.From.FingerPrint, "rsn", await bc.GetPlayerName(bc.From.Nickname)); } string publicSkill = "1"; if (state == "off") { publicSkill = "0"; } await Database.Update("users", "fingerprint='" + bc.From.FingerPrint + "'", "publicSkill", publicSkill); await bc.SendReply("Your public trigger-only command have been turned " + state + "."); }
private static async Task _SetSpeed(CommandContext bc) { if (bc.MessageTokens.Length < 4) { await bc.SendReply("Syntax: !set speed <skill> <average exp. per hour>"); return; } string skill = Skill.OVER; if (!Skill.TryParse(bc.MessageTokens[2], ref skill)) { await bc.SendReply("Error: Invalid skill name."); return; } string speed = bc.MessageTokens[3].ToLowerInvariant(); if (!Regex.Match(speed, @"\d+(?:\.\d+)?(?:m|k)?").Success) { await bc.SendReply("Error: Invalid average exp. per hour."); return; } // Add this player to database if he never set a default name. if (await Database.Lookup<long>("COUNT(*)", "users", "fingerprint=@fp", new[] { new MySqlParameter("@fp", bc.From.FingerPrint) }) < 1) { await Database.Insert("users", "fingerprint", bc.From.FingerPrint, "rsn", await bc.GetPlayerName(bc.From.Nickname)); } int speedValue = speed.ToInt32(); await Database.SetStringParameter("users", "speeds", "fingerprint='" + bc.From.FingerPrint + "'", skill, speedValue.ToStringI()); if (speedValue > 0) { await bc.SendReply(@"Your speed for \b{0}\b is currently set to \u{1} average exp. per hour\u.", skill, speedValue.ToShortString(1)); } else { await bc.SendReply(@"Your speed for \b{0}\b was deleted.", skill); } }
private static async Task _SetItem(CommandContext bc) { if (bc.MessageTokens.Length < 4) { await bc.SendReply("Syntax: !set item <skill> <item>"); return; } string skill = Skill.OVER; if (!Skill.TryParse(bc.MessageTokens[2], ref skill)) { await bc.SendReply("Error: Invalid skill name."); return; } string item = bc.MessageTokens.Join(3).Replace(";", string.Empty).ToLowerInvariant(); // Add this player to database if he never set a default name. if (await Database.Lookup<long>("COUNT(*)", "users", "fingerprint=@fp", new[] { new MySqlParameter("@fp", bc.From.FingerPrint) }) < 1) { await Database.Insert("users", "fingerprint", bc.From.FingerPrint, "rsn", await bc.GetPlayerName(bc.From.Nickname)); } await Database.SetStringParameter("users", "items", "fingerprint='" + bc.From.FingerPrint + "'", skill, item); await bc.SendReply(@"Your default item for \b{0}\b is currently set to \u{1}\u.", skill, item); }
public static async Task Stats(CommandContext bc) { // get @next var nextMatch = _nextRegex.Match(bc.Message); if (nextMatch.Success) { bc.Message = bc.Message.Replace(nextMatch.Value, string.Empty); } // get @experience var expMatch = _expRegex.Match(bc.Message); if (expMatch.Success) { bc.Message = bc.Message.Replace(expMatch.Value, string.Empty); } // get @rank var rankMatch = _rankRegex.Match(bc.Message); if (rankMatch.Success) { bc.Message = bc.Message.Replace(rankMatch.Value, string.Empty); } // get @virtuallevel var virtualMatch = _virtualRegex.Match(bc.Message); if (virtualMatch.Success) { bc.Message = bc.Message.Replace(virtualMatch.Value, string.Empty); } // get < var lessThan = 0; var lessThanMatch = _lessThanRegex.Match(bc.Message); if (lessThanMatch.Success) { lessThan = int.Parse(lessThanMatch.Groups[1].Value, CultureInfo.InvariantCulture); switch (lessThanMatch.Groups[2].Value) { case "m": lessThan *= 1000000; break; case "k": lessThan *= 1000; break; } if (lessThan < 127) { lessThan = lessThan.ToExp(); } bc.Message = bc.Message.Replace(lessThanMatch.Value, string.Empty); } // get > var greaterThan = 0; var greaterThanMatch = _greaterThanRegex.Match(bc.Message); if (greaterThanMatch.Success) { greaterThan = int.Parse(greaterThanMatch.Groups[1].Value, CultureInfo.InvariantCulture); switch (greaterThanMatch.Groups[2].Value) { case "m": greaterThan *= 1000000; break; case "k": greaterThan *= 1000; break; } if (greaterThan < 126) { greaterThan = (greaterThan + 1).ToExp(); } bc.Message = bc.Message.Replace(greaterThanMatch.Value, string.Empty); } // get player var player = await Player.FromHiscores(await bc.GetPlayerName(bc.MessageTokens.Length == 1 ? bc.From.Nickname : bc.MessageTokens.Join(1))); if (!player.Ranked) { await bc.SendReply(@"\b{0}\b doesn't feature Hiscores.", player.Name); return; } // !all @next if (nextMatch.Success) { var i = 0; await bc.SendReply(from skill in player.Skills.SortedByExpToNextVLevel group skill by i++ / 13 into skills select skills.Aggregate( new StringBuilder(512).AppendFormat(@"\b{0}\b exp. to next level:", player.Name), (sb, skill) => sb.AppendFormat(@"\c{0} {1:N0}\c {2};", skill.VLevel >= skill.MaxLevel ? 4 : 3, skill.ExpToVLevel, skill.Name) )); return; } // select non meta player skills var playerSkills = player.Skills.Values.Where(s => s.Name != Skill.OVER && s.Name != Skill.COMB).ToList(); // calculate overall max level and exp var maxOverallLevel = 0; var maxOverallExp = 0L; if (virtualMatch.Success) { maxOverallLevel = 126 * playerSkills.Count; maxOverallExp = 200000000L * playerSkills.Count; } else { foreach (var skill in playerSkills) { maxOverallLevel += skill.MaxLevel; maxOverallExp += skill.MaxLevel.ToExp(); } } // calculate overall and average levels var overallLevel = virtualMatch.Success ? playerSkills.Sum(skill => skill.VLevel) : player.Skills[Skill.OVER].Level; var avgSkillLevel = (double) overallLevel / playerSkills.Count; var averageExp = player.Skills[Skill.OVER].Exp / playerSkills.Count; var reply = new StringBuilder(512) .AppendFormat(@"\b{0}\b \c7{1:n}\c | level:\c7 {2:N0}\c (\c07{3:N1}\c avg) | exp:\c7 {1:e}\c (\c07{4:0.#%}\c of {5}) | rank:\c7 {1:R}\c", player.Name, player.Skills[Skill.OVER], overallLevel, avgSkillLevel, (double) player.Skills[Skill.OVER].Exp / maxOverallExp, maxOverallLevel); // add SS rank if applicable var ssPlayers = (await Players.FromClan("SS")).OrderBy(p => p.Skills[Skill.OVER]); var ssRank = ssPlayers.FindIndex(p => p.Name.EqualsI(player.Name)); if (ssRank != -1) { reply.AppendFormat(@" (SS rank: \c07{0}\c)", ssRank + 1); } // output overall information await bc.SendReply(reply); // output skills var format = @" {2}\c{1:00}{0:r"; if (expMatch.Success) { format += 'e'; } else if (virtualMatch.Success) { format += 'v'; } else if (!rankMatch.Success) { format += 'l'; } format += @"}\c {0:n}{2};"; var avgExpThreshold = averageExp / 5; var highestExp = playerSkills.Max(s => s.Exp); var filteredSkills = playerSkills.Where(s => (lessThan == 0 || s.Exp < lessThan) && (greaterThan == 0 || s.Exp > greaterThan)).ToList(); await bc.SendReply(filteredSkills.Where(s => s.IsCombat).Concat(player.Skills[Skill.COMB]).Aggregate( new StringBuilder(@"\uCombat skills\u:", 512), (sb, s) => sb.AppendFormat(format, s, s.Exp > averageExp + avgExpThreshold ? 3 : (s.Exp < averageExp - avgExpThreshold ? 4 : 7), s.Exp == highestExp ? @"\u" : string.Empty) ).AppendFormat(@" (\c7{0}\c)", player.CombatClass)); await bc.SendReply(filteredSkills.Where(s => !s.IsCombat).AggregateOrDefault( new StringBuilder(@"\uOther skills\u:", 512), (sb, s) => sb.AppendFormat(format, s, s.Exp > averageExp + avgExpThreshold ? 3 : (s.Exp < averageExp - avgExpThreshold ? 4 : 7), s.Exp == highestExp ? @"\u" : string.Empty) )); // output activities if (lessThan == 0 && greaterThan == 0) { await bc.SendReply(player.Activities.Values.Where(a => a.Rank > 0).AggregateOrDefault( new StringBuilder(@"\uActivities\u:", 512), (sb, a) => sb.AppendFormat(@"\c7 {0:N0}\c {1};", rankMatch.Success ? a.Rank : a.Score, a.Name) )); } }
public static async Task SlayerPercent(CommandContext bc) { // get rsn string rsn; if (bc.MessageTokens.Length > 1) { rsn = await bc.GetPlayerName(bc.MessageTokens.Join(1)); } else { rsn = await bc.GetPlayerName(bc.From.Nickname); } var p = await Player.FromHiscores(rsn); if (!p.Ranked) { await bc.SendReply(@"\b{0}\b doesn't feature Hiscores.", rsn); return; } long hits_exp_gained = p.Skills[Skill.HITP].Exp - 1154; double expected_max_slayer_exp = hits_exp_gained * 3.0 / 4.0; await bc.SendReply(@"\b{0}\b \c07{1:0.##}% - {2:0.##}%\c of combat exp. is slayer based, with \c07{3:N0}\c combat slayer exp. and \c07{4:N0}\c combat total exp. (This percentage isn't accurate, mostly because of monster hp regeneration ratio and cannon slayering.)", rsn, (double) p.Skills[Skill.SLAY].Exp / expected_max_slayer_exp * 100.0, (double) p.Skills[Skill.SLAY].Exp / (expected_max_slayer_exp - ((double) hits_exp_gained / 133.0)) * 100.0, (double) p.Skills[Skill.SLAY].Exp * 16.0 / 3.0, hits_exp_gained + hits_exp_gained * 3); }
public static async Task Performance(CommandContext bc) { bool showAll = false; if (bc.Message.Contains(" @all")) { showAll = true; bc.Message = bc.Message.Replace(" @all", string.Empty); } // get rsn string rsn; if (bc.MessageTokens.Length > 1) { rsn = await bc.GetPlayerName(bc.MessageTokens.Join(1)); } else { rsn = await bc.GetPlayerName(bc.From.Nickname); } // get this player last update time DateTime lastupdate; var dblastupdate = await Database.LastUpdate(rsn); if (dblastupdate == null || dblastupdate.Length < 8) { lastupdate = DateTime.UtcNow.AddHours(-DateTime.UtcNow.Hour + 6).AddMinutes(-DateTime.UtcNow.Minute).AddSeconds(-DateTime.UtcNow.Second); if (DateTime.UtcNow.Hour >= 0 && DateTime.UtcNow.Hour < 6) { lastupdate = lastupdate.AddDays(-1); } } else { lastupdate = dblastupdate.ToDateTime(); } // get performance interval int days; string interval; DateTime firstday, lastday; if (bc.MessageTokens[0].Contains("yesterday") || bc.MessageTokens[0].Contains("yday")) { interval = "Yesterday"; lastday = lastupdate; firstday = lastday.AddDays(-1); days = 1; } else if (bc.MessageTokens[0].Contains("lastweek") | bc.MessageTokens[0].Contains("lweek")) { interval = "Last week"; lastday = lastupdate.AddDays(-((int) lastupdate.DayOfWeek)); firstday = lastday.AddDays(-7); days = 7; } else if (bc.MessageTokens[0].Contains("lastmonth") | bc.MessageTokens[0].Contains("lmonth")) { interval = "Last month"; lastday = lastupdate.AddDays(1 - lastupdate.Day); firstday = lastday.AddMonths(-1); days = (lastday - firstday).Days; } else if (bc.MessageTokens[0].Contains("lastyear") | bc.MessageTokens[0].Contains("lyear")) { interval = "Last year"; lastday = lastupdate.AddDays(1 - lastupdate.DayOfYear); firstday = lastday.AddYears(-1); days = (lastday - firstday).Days; } else if (bc.MessageTokens[0].Contains("week")) { interval = "Week"; firstday = lastupdate.AddDays(-((int) lastupdate.DayOfWeek)); lastday = DateTime.MaxValue; days = (int) lastupdate.DayOfWeek + 1; } else if (bc.MessageTokens[0].Contains("month")) { interval = "Month"; firstday = lastupdate.AddDays(1 - lastupdate.Day); lastday = DateTime.MaxValue; days = lastupdate.Day; } else if (bc.MessageTokens[0].Contains("year")) { interval = "Year"; firstday = lastupdate.AddDays(1 - lastupdate.DayOfYear); lastday = DateTime.MaxValue; days = lastupdate.DayOfYear; } else if (bc.MessageTokens[0].Contains("today")) { interval = "Today"; firstday = lastupdate; lastday = DateTime.MaxValue; days = 1; } else { Match M = Regex.Match(bc.MessageTokens[0], "last(\\d+)days"); if (M.Success) { days = int.Parse(M.Groups[1].Value, CultureInfo.InvariantCulture); interval = "Last " + days + " days"; lastday = lastupdate; firstday = lastday.AddDays(-days); } else { return; } } // Get old player var PlayerOld = await Player.FromDatabase(rsn, firstday); if (!PlayerOld.Ranked) { // Get data from RuneScript PlayerOld = new Player(rsn, (int) (DateTime.UtcNow - firstday).TotalSeconds); await bc.SendReply(@"\c07{0}\c information retrieved from RuneScript database. (This data may not be 100% accurate)", firstday.ToStringI("yyyy/MMM/dd")); if (!PlayerOld.Ranked) { await bc.SendReply(@"\b{0}\b wasn't being tracked on \c07{1}\c.", rsn, firstday.ToStringI("yyyy/MMM/dd")); return; } foreach (Skill skill in PlayerOld.Skills.Values) { PlayerOld.Skills[skill.Name].Level = Math.Max(0, skill.Level); } } // Get new player Player PlayerNew; if (lastday == DateTime.MaxValue) { PlayerNew = await Player.FromHiscores(rsn); } else { PlayerNew = await Player.FromDatabase(rsn, lastday); } if (!PlayerNew.Ranked) { if (lastday == DateTime.MaxValue) { await bc.SendReply(@"\b{0}\b doesn't feature Hiscores.", rsn); return; } // Get data from RuneScript PlayerNew = new Player(rsn, (int) (DateTime.UtcNow - lastday).TotalSeconds); await bc.SendReply(@"\c07{0}\c information retrieved from RuneScript database. (This data may not be 100% accurate)", lastday.ToStringI("yyyy/MMM/dd")); if (!PlayerNew.Ranked) { await bc.SendReply(@"\b{0}\b wasn't being tracked on \c07{1}\c.", rsn, lastday.ToStringI("yyyy/MMM/dd")); return; } } // 1st line: overall / combat string ReplyMsg = @"\b{0}\b \u{1}\u skills:".FormatWith(rsn, interval.ToLowerInvariant()); Skill OverallDif = PlayerNew.Skills[Skill.OVER] - PlayerOld.Skills[Skill.OVER]; if (OverallDif.Exp <= 0) { await bc.SendReply(@"No performance for \b{0}\b within this period.", rsn); } else { Skill CombatDif = PlayerNew.Skills[Skill.COMB] - PlayerOld.Skills[Skill.COMB]; string DifLevel = string.Empty; if (OverallDif.Level > 0) { DifLevel = @" [\b+{0}\b]".FormatWith(OverallDif.Level); } if (days == 1) { ReplyMsg += @" \c07Overall\c lvl {0} \c03+{1}\c xp (Avg. hourly exp.: \c07{2}\c)".FormatWith(PlayerNew.Skills[Skill.OVER].Level + DifLevel, OverallDif.Exp.ToShortString(1), (OverallDif.Exp / 24.0).ToShortString(0)); } else { ReplyMsg += @" \c07Overall\c lvl {0} \c03+{1}\c xp (Avg. daily exp.: \c07{2}\c)".FormatWith(PlayerNew.Skills[Skill.OVER].Level + DifLevel, OverallDif.Exp.ToShortString(1), (OverallDif.Exp / (double) days).ToShortString(0)); } DifLevel = string.Empty; if (CombatDif.Level > 0) { DifLevel = @" [\b+{0}\b]".FormatWith(CombatDif.Level); } ReplyMsg += @"; \c07Combat\c lvl {0} \c03+{1}\c xp (\c07{2}%\c)".FormatWith(PlayerNew.Skills[Skill.COMB].Level + DifLevel, CombatDif.Exp.ToShortString(1), (CombatDif.Exp / (double) OverallDif.Exp * 100.0).ToShortString(1)); ReplyMsg += @"; Interval: \c07{0}\c -> \c07{1}\c".FormatWith(firstday.ToStringI("yyyy/MMM/dd"), lastday == DateTime.MaxValue ? "Now" : lastday.ToStringI("yyyy/MMM/dd")); await bc.SendReply(ReplyMsg); // 2nd line: skills list List<Skill> SkillsDif = (from SkillNow in PlayerNew.Skills.Values where SkillNow.Name != Skill.OVER && SkillNow.Name != Skill.COMB select SkillNow - PlayerOld.Skills[SkillNow.Name]).ToList(); SkillsDif.Sort(); int skillLength = showAll ? SkillsDif.Count : 10; bool has_performance = false; ReplyMsg = @"\b{0}\b \u{1}\u skills:".FormatWith(rsn, interval.ToLowerInvariant()); for (int i = 0; i < skillLength; i++) { if (SkillsDif[i].Exp > 0) { has_performance = true; DifLevel = string.Empty; if (SkillsDif[i].Level > 0) { DifLevel = @" [\b+{0}\b]".FormatWith(SkillsDif[i].Level); } ReplyMsg += @" \c07{0}\c lvl {1} \c3+{2}\c xp;".FormatWith(SkillsDif[i].Name, PlayerNew.Skills[SkillsDif[i].Name].Level + DifLevel, SkillsDif[i].Exp.ToShortString(1)); } if ((i + 1) % 10 == 0) { await bc.SendReply(ReplyMsg); has_performance = false; ReplyMsg = @"\b{0}\b \u{1}\u skills:".FormatWith(rsn, interval.ToLowerInvariant()); } } if (has_performance) { await bc.SendReply(ReplyMsg); } // 3rd line: activities list List<Activity> activitiesDelta = (from newActivity in PlayerNew.Activities.Values where PlayerOld.Activities.ContainsKey(newActivity.Name) select newActivity - PlayerOld.Activities[newActivity.Name]).ToList(); activitiesDelta.Sort(); if (activitiesDelta.Count > 0) { has_performance = false; ReplyMsg = @"\b{0}\b \u{1}\u activities:".FormatWith(rsn, interval.ToLowerInvariant()); foreach (Activity t in activitiesDelta) { if (t.Score > 0) { has_performance = true; ReplyMsg += @" \c07{0}\c \c3+{1}\c score;".FormatWith(t.Name, t.Score); } } if (has_performance) { await bc.SendReply(ReplyMsg); } } } }
public static async Task SoulWars(CommandContext bc) { // get rsn string rsn = string.Empty; string skill = string.Empty; int level = 0; if (bc.MessageTokens.Length == 2) { rsn = await bc.GetPlayerName(bc.From.Nickname); Skill.TryParse(bc.MessageTokens[1], ref skill); } else if (bc.MessageTokens.Length == 3) { if (int.TryParse(bc.MessageTokens[1], out level)) { Skill.TryParse(bc.MessageTokens[2], ref skill); } else if (int.TryParse(bc.MessageTokens[2], out level)) { Skill.TryParse(bc.MessageTokens[1], ref skill); } else { if (Skill.TryParse(bc.MessageTokens[1], ref skill)) { rsn = await bc.GetPlayerName(bc.MessageTokens[2]); } else if (Skill.TryParse(bc.MessageTokens[2], ref skill)) { rsn = await bc.GetPlayerName(bc.MessageTokens[1]); } } } else if (bc.MessageTokens.Length > 3) { if (Skill.TryParse(bc.MessageTokens[1], ref skill)) { rsn = await bc.GetPlayerName(bc.MessageTokens.Join(2).Trim()); } else if (Skill.TryParse(bc.MessageTokens[bc.MessageTokens.Length - 1], ref skill)) { bc.MessageTokens[bc.MessageTokens.Length - 1] = string.Empty; rsn = await bc.GetPlayerName(bc.MessageTokens.Join(1).Trim()); } } if (string.IsNullOrEmpty(skill) || (string.IsNullOrEmpty(rsn) && level == 0)) { await bc.SendReply("Syntax: !soulwars <level> <skill>"); return; } if (!string.IsNullOrEmpty(rsn)) { var p = await Player.FromHiscores(rsn); if (!p.Ranked) { await bc.SendReply(@"\b{0}\b doesn't feature Hiscores.", rsn); return; } Skill skillInfo = p.Skills[skill]; level = skillInfo.Level; } switch (skill) { case Skill.ATTA: case Skill.STRE: case Skill.DEFE: case Skill.HITP: case Skill.RANG: case Skill.MAGI: case Skill.PRAY: case Skill.SLAY: int exp = Utils.SoulWarsExpPerZeal(skill, level); await bc.SendReply(@"For each point at level \c07{0}\c you will gain \c07{1:N0} {2}\c experience.", level, exp, skill); break; default: await bc.SendReply("You can only calculate experience for Attack, Strength, Defence, Constitution, Prayer and Slayer at the moment."); break; } }
public static async Task Compare(CommandContext bc) { if (bc.MessageTokens.Length == 1) { await bc.SendReply("Syntax: !compare [skill] <player1> [player2]"); return; } string skill1 = null, activity1 = null; string rsn1, rsn2; if (Skill.TryParse(bc.MessageTokens[1], ref skill1)) { if (bc.MessageTokens.Length == 3) { // !compare <skill> <player2> rsn1 = await bc.GetPlayerName(bc.From.Nickname); rsn2 = await bc.GetPlayerName(bc.MessageTokens[2]); } else if (bc.MessageTokens.Length > 3) { // !compare <skill> <player1> <player2> rsn1 = await bc.GetPlayerName(bc.MessageTokens[2]); rsn2 = await bc.GetPlayerName(bc.MessageTokens.Join(3)); } else { // !compare <player2> skill1 = Skill.OVER; rsn1 = await bc.GetPlayerName(bc.From.Nickname); rsn2 = await bc.GetPlayerName(bc.MessageTokens[1]); } } else if (Bot.Activity.TryParse(bc.MessageTokens[1], ref activity1)) { if (bc.MessageTokens.Length == 3) { // !compare <activity> <player2> rsn1 = await bc.GetPlayerName(bc.From.Nickname); rsn2 = await bc.GetPlayerName(bc.MessageTokens[2]); } else if (bc.MessageTokens.Length > 3) { // !compare <activity> <player1> <player2> rsn1 = await bc.GetPlayerName(bc.MessageTokens[2]); rsn2 = await bc.GetPlayerName(bc.MessageTokens.Join(3)); } else { // !compare <player2> skill1 = Skill.OVER; rsn1 = await bc.GetPlayerName(bc.From.Nickname); rsn2 = await bc.GetPlayerName(bc.MessageTokens[1]); } } else if (bc.MessageTokens.Length == 2) { // !compare <player2> skill1 = Skill.OVER; rsn1 = await bc.GetPlayerName(bc.From.Nickname); rsn2 = await bc.GetPlayerName(bc.MessageTokens[1]); } else { // !compare <player1> <player2> skill1 = Skill.OVER; rsn1 = await bc.GetPlayerName(bc.MessageTokens[1]); rsn2 = await bc.GetPlayerName(bc.MessageTokens.Join(2)); } var p1 = await Player.FromHiscores(rsn1); if (!p1.Ranked) { await bc.SendReply(@"\b{0}\b doesn't feature Hiscores.", rsn1); return; } var p2 = await Player.FromHiscores(rsn2); if (!p2.Ranked) { await bc.SendReply(@"\b{0}\b doesn't feature Hiscores.", rsn2); return; } string reply; if (activity1 == null) { // compare skills Skill pskill1 = p1.Skills[skill1]; Skill pskill2 = p2.Skills[skill1]; if (pskill1.Level == pskill2.Level) { reply = @"Both \b{0}\b and \b{1}\b have level \c07{2}\c".FormatWith(p1.Name, p2.Name, pskill1.Level); if (pskill1.Exp == pskill2.Exp) { reply += @" and \c07{0:e}\c experience.".FormatWith(pskill1); } else if (pskill1.Exp > pskill2.Exp) { reply += @", but \b{0}\b has \c07{1:N0}\c more experience.".FormatWith(p1.Name, pskill1.Exp - pskill2.Exp); } else { reply += @", but \b{0}\b has \c07{1:N0}\c less experience.".FormatWith(p1.Name, pskill2.Exp - pskill1.Exp); } } else if (pskill1.Level > pskill2.Level) { reply = @"\b{0}\b has \c07{2}\c more level{3} than \b{1}\b.".FormatWith(p1.Name, p2.Name, pskill1.Level - pskill2.Level, pskill1.Level - pskill2.Level == 1 ? string.Empty : "s"); if (pskill1.Exp == pskill2.Exp) { reply += @", but both have \c07{0:e}\c experience.".FormatWith(pskill1); } else if (pskill1.Exp > pskill2.Exp) { reply += @" and has \c07{0:N0}\c more experience.".FormatWith(pskill1.Exp - pskill2.Exp); } else { reply += @", but \b{0}\b has \c07{1:N0}\c less experience.".FormatWith(p1.Name, pskill2.Exp - pskill1.Exp); } } else { reply = @"\b{0}\b has \c07{2}\c less level{3} than \b{1}\b.".FormatWith(p1.Name, p2.Name, pskill2.Level - pskill1.Level, pskill2.Level - pskill1.Level == 1 ? string.Empty : "s"); if (pskill1.Exp == pskill2.Exp) { reply += @", but both have \c07{0:e}\c experience.".FormatWith(pskill1); } else if (pskill1.Exp > pskill2.Exp) { reply += @", but \b{0}\b has \c07{1:N0}\c more experience.".FormatWith(p1.Name, pskill1.Exp - pskill2.Exp); } else { reply += @" and has \c07{0:N0}\c less experience.".FormatWith(pskill2.Exp - pskill1.Exp); } } await bc.SendReply(reply); // get these players last update time var dblastupdate = await Database.LastUpdate(rsn1); if (dblastupdate != null && dblastupdate.Length == 8) { p1 = await Player.FromDatabase(rsn1, dblastupdate.ToDateTime()); if (p1.Ranked) { dblastupdate = await Database.LastUpdate(rsn2); if (dblastupdate != null && dblastupdate.Length == 8) { p2 = await Player.FromDatabase(rsn2, dblastupdate.ToDateTime()); if (p2.Ranked) { Skill skilldif1 = pskill1 - p1.Skills[skill1]; Skill skilldif2 = pskill2 - p2.Skills[skill1]; await bc.SendReply(@"Today \b{0}\b did \c07{1:e}\c exp. while \b{2}\b did \c07{3:e}\c exp.", rsn1, skilldif1, rsn2, skilldif2); } } } } } else { // compare activities Activity p1Activity = p1.Activities[activity1]; Activity p2Activity = p2.Activities[activity1]; if (p1Activity.Rank == -1) { await bc.SendReply(@"\b{0}\b doesn't feature Hiscores.", rsn1); return; } if (p2Activity.Rank == -1) { await bc.SendReply(@"\b{0}\b doesn't feature Hiscores.", rsn2); return; } if (p1Activity.Score == p2Activity.Score) { reply = @"Both \b{0}\b and \b{1}\b have \c07{2}\c score.".FormatWith(rsn1, rsn2, p1Activity.Score); } else if (p1Activity.Score > p2Activity.Score) { reply = @"\b{0}\b has \c07{2}\c more score than \b{1}\b.".FormatWith(rsn1, rsn2, p1Activity.Score - p2Activity.Score); } else { reply = @"\b{0}\b has \c07{2}\c less score than \b{1}\b.".FormatWith(rsn1, rsn2, p2Activity.Score - p1Activity.Score); } await bc.SendReply(reply); // get these players last update time var dblastupdate = await Database.LastUpdate(rsn1); if (dblastupdate != null && dblastupdate.Length == 8) { p1 = await Player.FromDatabase(rsn1, dblastupdate.ToDateTime()); if (p1.Ranked && p1.Activities[activity1].Rank > 0) { dblastupdate = await Database.LastUpdate(rsn2); if (dblastupdate != null && dblastupdate.Length == 8) { p2 = await Player.FromDatabase(rsn2, dblastupdate.ToDateTime()); if (p2.Ranked && p2.Activities[activity1].Rank > 0) { Activity p1ActivityDelta = p1Activity - p1.Activities[activity1]; Activity p2ActivityDelta = p2Activity - p2.Activities[activity1]; await bc.SendReply(@"Today \b{0}\b did \c07{1:s}\c score while \b{2}\b did \c07{3:s}\c score.", rsn1, p1ActivityDelta, rsn2, p2ActivityDelta); } } } } } }
public static async Task End(CommandContext bc) { // get rsn string rsn = await bc.GetPlayerName(bc.From.Nickname); var p = await Player.FromHiscores(rsn); if (!p.Ranked) { await bc.SendReply(@"\b{0}\b doesn't feature Hiscores.", rsn); return; } // get @set or @save bool set = bc.Message.ContainsI("@set") || bc.Message.ContainsI("@save"); if (set) { bc.Message = Regex.Replace(bc.Message, @"\s*@s(?:et|ave)\s*", string.Empty); } // get timer name string name = string.Empty; int indexOfSharp = bc.Message.IndexOf('#'); if (indexOfSharp > 0) { name = bc.Message.Substring(indexOfSharp + 1); bc.Message = bc.Message.Substring(0, indexOfSharp - 1); } var rs = await Database.FetchFirst("SELECT skill,exp,datetime FROM timers_exp WHERE fingerprint=@fingerprint AND name=@name LIMIT 1", new MySqlParameter("@fingerprint", bc.From.FingerPrint), new MySqlParameter("@name", name)); if (rs != null) { string skill = rs.GetString(0); var gainedExp = p.Skills[skill].Exp - (uint) rs["exp"]; TimeSpan time = DateTime.UtcNow - rs.GetString(2).ToDateTime(); string reply = @"You gained \c07{0:N0}\c \u{1}\u exp in \c07{2}\c. That's \c07{3:N0}\c exp/h.".FormatWith(gainedExp, skill.ToLowerInvariant(), time.ToLongString(), (double) gainedExp / time.TotalHours); if (gainedExp > 0 && skill != Skill.OVER && skill != Skill.COMB && p.Skills[skill].VLevel < 126) { reply += @" Estimated time to level up: \c07{0}\c".FormatWith(TimeSpan.FromSeconds(p.Skills[skill].ExpToVLevel / (gainedExp / time.TotalSeconds)).ToLongString()); } await bc.SendReply(reply); if (gainedExp > 0) { // Add this player to database if he never set a default name. if (await Database.Lookup<long>("COUNT(*)", "users", "fingerprint=@fp", new[] { new MySqlParameter("@fp", bc.From.FingerPrint) }) < 1) { await Database.Insert("users", "fingerprint", bc.From.FingerPrint, "rsn", await bc.GetPlayerName(bc.From.Nickname)); } // Set exp. made in an hour in this skill. await Database.SetStringParameter("users", "speeds", "fingerprint='" + bc.From.FingerPrint + "'", skill, ((int) (gainedExp / time.TotalHours)).ToStringI()); } // remove the timer with this name await Database.ExecuteNonQuery("DELETE FROM timers_exp WHERE fingerprint='" + bc.From.FingerPrint + "' AND name='" + name.Replace("'", "''") + "'"); } else { if (name.Length > 0) { await bc.SendReply("You must start timing a skill on that timer first."); } else { await bc.SendReply("You must start timing a skill first."); } } }
public static async Task PcPercent(CommandContext bc) { // get rsn string rsn; if (bc.MessageTokens.Length > 1) { rsn = await bc.GetPlayerName(bc.MessageTokens.Join(1)); } else { rsn = await bc.GetPlayerName(bc.From.Nickname); } var p = await Player.FromHiscores(rsn); if (!p.Ranked) { await bc.SendReply(@"\b{0}\b doesn't feature Hiscores.", rsn); return; } long expected_combat_xp = p.Skills[Skill.HITP].Exp + p.Skills[Skill.HITP].Exp * 12 / 4; long current_combat_xp = p.Skills[Skill.HITP].Exp + p.Skills[Skill.ATTA].Exp + p.Skills[Skill.STRE].Exp + p.Skills[Skill.DEFE].Exp + p.Skills[Skill.RANG].Exp; await bc.SendReply(@"\b{0}\b \c07{1:0.##}%\c of combat exp. was pest controled and/or cannoned, with \c07{2:N0}\c normal combat exp. and \c07{3:N0}\c total combat exp. (This percentage might not be accurate; magic isn't included in calculations.)", rsn, (double) (current_combat_xp - expected_combat_xp) / (double) current_combat_xp * 100.0, expected_combat_xp, current_combat_xp); }
public static async Task Combat(CommandContext bc) { // get @next var nextMatch = _nextRegex.Match(bc.Message); if (nextMatch.Success) { bc.Message = bc.Message.Replace(nextMatch.Value, string.Empty); } // get @experience var expMatch = _expRegex.Match(bc.Message); if (expMatch.Success) { bc.Message = bc.Message.Replace(expMatch.Value, string.Empty); } // get @rank var rankMatch = _rankRegex.Match(bc.Message); if (rankMatch.Success) { bc.Message = bc.Message.Replace(rankMatch.Value, string.Empty); } // get @virtuallevel var virtualMatch = _virtualRegex.Match(bc.Message); if (virtualMatch.Success) { bc.Message = bc.Message.Replace(virtualMatch.Value, string.Empty); } // get player var player = await Player.FromHiscores(await bc.GetPlayerName(bc.MessageTokens.Length == 1 ? bc.From.Nickname : bc.MessageTokens.Join(1))); if (!player.Ranked) { await bc.SendReply(@"\b{0}\b doesn't feature Hiscores.", player.Name); return; } var playerSkills = player.Skills.Values.Where(s => s.Name != Skill.OVER && s.Name != Skill.COMB).ToList(); var averageExp = player.Skills[Skill.OVER].Exp / playerSkills.Count; var avgExpThreshold = averageExp / 5; var highestLevelExp = playerSkills.Max(s => s.Exp); var expectedMaxSlayerExp = (int) ((player.Skills[Skill.HITP].Exp - 1154) * 3 / 4.0); var combatClass = Utils.CombatClass(player.Skills, virtualMatch.Success); var combatLevel = Utils.CalculateCombat(player.Skills, virtualMatch.Success); var reply = new StringBuilder(512) .AppendFormat(@"\b{0}\b \c07combat\c | level: \c07{1}\c | exp: \c07{2:e}\c | combat%: \c07{3:0.##}%\c | slayer%: \c07{4:0.##}%\c | class: \c07{5}\c", player.Name, combatLevel, player.Skills[Skill.COMB], (double) player.Skills[Skill.COMB].Exp / (double) player.Skills[Skill.OVER].Exp * 100.0, (double) player.Skills[Skill.SLAY].Exp / (double) expectedMaxSlayerExp * 100.0, combatClass); // Add SS rank if applicable var ssPlayers = (await Players.FromClan("SS")).OrderBy(p => p.Skills[Skill.COMB]); var ssRank = ssPlayers.FindIndex(p => p.Name.EqualsI(player.Name)); if (ssRank != -1) { reply.AppendFormat(@" (SS rank: \c07{0}\c)", ssRank + 1); } await bc.SendReply(reply); var format = @" {2}\c{1:00}{0:r"; if (expMatch.Success) { format += 'e'; } else if (virtualMatch.Success) { format += 'v'; } else if (!rankMatch.Success) { format += 'l'; } format += @"}{3}\c {0:n}{2};"; reply = new StringBuilder(rankMatch.Success ? @"\uSkills\u:" : @"\uSkills (to level)\u:", 512); foreach (var s in player.Skills.Values.Where(s => s.IsCombat)) { var next = 0; if (!rankMatch.Success) { switch (s.Name) { case Skill.ATTA: next = virtualMatch.Success ? Utils.NextCombatAttack(player.Skills[Skill.ATTA].VLevel, player.Skills[Skill.STRE].VLevel, player.Skills[Skill.DEFE].VLevel, player.Skills[Skill.RANG].VLevel, player.Skills[Skill.MAGI].VLevel) : Utils.NextCombatAttack(player.Skills[Skill.ATTA].Level, player.Skills[Skill.STRE].Level, player.Skills[Skill.DEFE].Level, player.Skills[Skill.RANG].Level, player.Skills[Skill.MAGI].Level); break; case Skill.STRE: next = virtualMatch.Success ? Utils.NextCombatStrength(player.Skills[Skill.ATTA].VLevel, player.Skills[Skill.STRE].VLevel, player.Skills[Skill.DEFE].VLevel, player.Skills[Skill.RANG].VLevel, player.Skills[Skill.MAGI].VLevel) : Utils.NextCombatStrength(player.Skills[Skill.ATTA].Level, player.Skills[Skill.STRE].Level, player.Skills[Skill.DEFE].Level, player.Skills[Skill.RANG].Level, player.Skills[Skill.MAGI].Level); break; case Skill.DEFE: next = virtualMatch.Success ? Utils.NextCombatDefence(player.Skills[Skill.ATTA].VLevel, player.Skills[Skill.STRE].VLevel, player.Skills[Skill.DEFE].VLevel, player.Skills[Skill.RANG].VLevel, player.Skills[Skill.MAGI].VLevel) : Utils.NextCombatDefence(player.Skills[Skill.ATTA].Level, player.Skills[Skill.STRE].Level, player.Skills[Skill.DEFE].Level, player.Skills[Skill.RANG].Level, player.Skills[Skill.MAGI].Level); break; case Skill.MAGI: next = virtualMatch.Success ? Utils.NextCombatMagic(player.Skills[Skill.ATTA].VLevel, player.Skills[Skill.STRE].VLevel, player.Skills[Skill.DEFE].VLevel, player.Skills[Skill.RANG].VLevel, player.Skills[Skill.MAGI].VLevel) : Utils.NextCombatMagic(player.Skills[Skill.ATTA].Level, player.Skills[Skill.STRE].Level, player.Skills[Skill.DEFE].Level, player.Skills[Skill.RANG].Level, player.Skills[Skill.MAGI].Level); break; case Skill.RANG: next = virtualMatch.Success ? Utils.NextCombatRanged(player.Skills[Skill.ATTA].VLevel, player.Skills[Skill.STRE].VLevel, player.Skills[Skill.DEFE].VLevel, player.Skills[Skill.RANG].VLevel, player.Skills[Skill.MAGI].VLevel) : Utils.NextCombatRanged(player.Skills[Skill.ATTA].Level, player.Skills[Skill.STRE].Level, player.Skills[Skill.DEFE].Level, player.Skills[Skill.RANG].Level, player.Skills[Skill.MAGI].Level); break; } } reply.AppendFormat(format, s, s.Exp > averageExp + avgExpThreshold ? 3 : (s.Exp < averageExp - avgExpThreshold ? 4 : 7), s.Exp == highestLevelExp ? @"\u" : string.Empty, next > 0 ? "(+" + next + ")" : string.Empty); } await bc.SendReply(reply); // Show player performance if applicable var dblastupdate = await Database.LastUpdate(player.Name); if (dblastupdate != null && dblastupdate.Length == 8) { DateTime lastupdate = dblastupdate.ToDateTime(); string perf; reply = new StringBuilder(512); var p_old = await Player.FromDatabase(player.Name, lastupdate); if (p_old.Ranked) { perf = _GetPerformance("Today", p_old.Skills[Skill.COMB], player.Skills[Skill.COMB]); if (perf != null) { reply.Append(perf + " | "); } } p_old = await Player.FromDatabase(player.Name, lastupdate.AddDays(-((int) lastupdate.DayOfWeek))); if (p_old.Ranked) { perf = _GetPerformance("Week", p_old.Skills[Skill.COMB], player.Skills[Skill.COMB]); if (perf != null) { reply.Append(perf + " | "); } } p_old = await Player.FromDatabase(player.Name, lastupdate.AddDays(1 - lastupdate.Day)); if (p_old.Ranked) { perf = _GetPerformance("Month", p_old.Skills[Skill.COMB], player.Skills[Skill.COMB]); if (perf != null) { reply.Append(perf + " | "); } } p_old = await Player.FromDatabase(player.Name, lastupdate.AddDays(1 - lastupdate.DayOfYear)); if (p_old.Ranked) { perf = _GetPerformance("Year", p_old.Skills[Skill.COMB], player.Skills[Skill.COMB]); if (perf != null) { reply.Append(perf + " | "); } } if (reply.Length > 0) { var r = reply.ToString(); await bc.SendReply(r.EndsWithI(" | ") ? r.Substring(0, r.Length - 3) : r); } } }
public static async Task Grats(CommandContext bc) { if (bc.MessageTokens.Length == 1) { await bc.SendReply("Syntax: !grats <skill> <level>"); return; } // get rsn var rsn = await bc.GetPlayerName(bc.From.Nickname); string skill = null; int level; if (int.TryParse(bc.MessageTokens[1], out level)) { if (bc.MessageTokens.Length > 2 && Skill.TryParse(bc.MessageTokens[2], ref skill)) { // !grats <level> <skill> } else { // !grats <level> await bc.SendReply("Syntax: !grats <skill> <level>"); return; } } else if (Skill.TryParse(bc.MessageTokens[1], ref skill)) { if (bc.MessageTokens.Length > 2 && int.TryParse(bc.MessageTokens[2], out level)) { // !grats <skill> <level> } else { // !grats <skill> var p = await Player.FromHiscores(rsn); if (p.Ranked) { level = p.Skills[skill].VLevel; } else { level = 0; } } } else { await bc.SendReply("Syntax: !grats <skill> <level>"); return; } if (skill == Skill.COMB) { level = Math.Min(138, level); } else if (skill != Skill.OVER) { level = Math.Min(126, level); } bc.ReplyNotice = false; if (level > 0) { await bc.SendReply(@":D\-< ¤.¡*°*¡.¤ Woo! Congrats on your \c07{0} level {1} {2}\c!! ¤.¡*°*¡.¤ :D/-<", skill.ToLowerInvariant(), level, rsn); } else { await bc.SendReply(@":D\-< ¤.¡*°*¡.¤ Woo! Congrats on your \c07{0} level {1}\c!! ¤.¡*°*¡.¤ :D/-<", skill.ToLowerInvariant(), rsn); } }
public static async Task PestControl(CommandContext bc) { if (bc.MessageTokens.Length == 1) { await bc.SendReply("Syntax: !pestcontrol <skill> [rsn] #<target>"); return; } string rsn = string.Empty; long target = 0; string skill = string.Empty; int points = 0; int rank = 0; // get target Match M = Regex.Match(bc.Message, @" #(n(?:l|r)|r?\d+(?:\.\d+)?(?:m|k)?)"); if (M.Success) { string goal = M.Groups[1].Value; if (goal.EqualsI("nl")) { target = 0; } else if (goal.EqualsI("nr")) { rank = -1; } else if (goal.StartsWithI("r")) { int goalRank = goal.Substring(1).ToInt32(); if (goalRank > 0 && goalRank <= 2000000) { rank = goalRank; } else { rank = -1; } } else { int goalLevel = goal.ToInt32(); if (goalLevel > 1 && goalLevel < 127) { target = goalLevel.ToExp(); } else if (goalLevel == 127) { target = 200000000; } else if (goalLevel > 127 && goalLevel <= 200000000) { target = goalLevel; } else { target = 0; } } bc.Message = Regex.Replace(bc.Message, @" #(n(?:l|r)|r?\d+(?:\.\d+)?(?:m|k)?)", string.Empty); } // get skill and rsn if (Skill.TryParse(bc.MessageTokens[1], ref skill)) { rsn = await bc.GetPlayerName(bc.MessageTokens.Join(2)); } else if (Skill.TryParse(bc.MessageTokens[bc.MessageTokens.Length - 1], ref skill)) { bc.MessageTokens[bc.MessageTokens.Length - 1] = string.Empty; rsn = await bc.GetPlayerName(bc.MessageTokens.Join(1).Trim()); } if (!string.IsNullOrEmpty(rsn)) { rsn = await bc.GetPlayerName(bc.From.Nickname); } if (string.IsNullOrEmpty(skill)) { await bc.SendReply("Syntax: !pestcontrol <skill> [rsn] #<target>"); return; } // find players exp var p = await Player.FromHiscores(rsn); if (!p.Ranked) { await bc.SendReply(@"\b{0}\b doesn't feature Hiscores.", rsn); return; } Skill skillInfo = p.Skills[skill]; // if target is a rank, find rank exp if (rank != 0) { if (rank == -1) { rank = skillInfo.Rank; } foreach (Skill s in new Hiscores(skill, null, rank)) { if (s.Rank == rank) { target = s.Exp + 1; break; } } } long curExp = skillInfo.Exp; int curLvl = skillInfo.Level; if (target == 0 || target <= curExp) { target = (skillInfo.VLevel + 1).ToExp(); } if (target > 200000000) { target = 200000000; } // count points double N; if (skill == "Prayer") { N = 18.0; } else if (skill == "Ranged" || skill == "Magic") { N = 32.0; } else { N = 35.0; } long potExp = curExp; var reply = new int[3]; for (int i = 0; i < 3; i++) { double bonus; int group; if (i == 0) { bonus = 1; group = 1; } else if (i == 1) { bonus = 1.01; group = 10; } else { bonus = 1.1; group = 100; } while (potExp <= target) { var pointExp = (int) (Math.Ceiling((curLvl + 25) * (double) (curLvl - 24) / 606.0) * N * bonus * group); while ((potExp.ToLevel() < curLvl + 1 || curLvl == 99) && potExp <= target) { potExp += pointExp; points = points + group; } curLvl = Math.Min(curLvl + 1, 99); } reply[i] = points; potExp = curExp; curLvl = skillInfo.Level; points = 0; } await bc.SendReply(@"PestControl points for \c07{0:N0}\c experience: \c07{1:N0}\c single points, \c07{2:N0}\c sets of 10 (\c07{3:N0}\c points), \c07{4:N0}\c sets of 100 (\c07{5:N0}\c points).", target - curExp, reply[0], reply[1] / 10, reply[1], reply[2] / 100, reply[2]); }
public static async Task HighLow(CommandContext bc) { // @rank bool rank = false; if (bc.Message.Contains(" @rank") || bc.Message.Contains(" @r")) { rank = true; bc.Message = bc.Message.Replace(" @rank", string.Empty); bc.Message = bc.Message.Replace(" @r", string.Empty); } // get rsn string rsn; if (bc.MessageTokens.Length > 1) { rsn = await bc.GetPlayerName(bc.MessageTokens.Join(1)); } else { rsn = await bc.GetPlayerName(bc.From.Nickname); } var p = await Player.FromHiscores(rsn); if (!p.Ranked) { await bc.SendReply(@"\b{0}\b doesn't feature Hiscores.", p.Name); return; } List<Skill> highest, lowest; int i; string reply; if (rank) { highest = p.Skills.HighestRanked; int highestRank = highest[0].Rank; reply = @"\b{0}\b \uhighest\u skills:".FormatWith(rsn); for (i = 0; i < highest.Count; i++) { if (highest[i].Rank != highestRank) { break; } reply += @" \c07{0}\c,".FormatWith(highest[i].Name); } reply = reply.Substring(0, reply.Length - 1) + @" level \c07{0:rv}\c ranked \c07#{0:r}\c".FormatWith(highest[0]); reply += @" \ufollowed by\u \c07{0:N}\c level \c07{0:rv}\c ranked \c07#{0:r}\c.".FormatWith(highest[i]); await bc.SendReply(reply); lowest = p.Skills.LowestRanked; int lowestRank = lowest[0].Rank; reply = @"\b{0}\b \ulowest\u skills:".FormatWith(rsn); for (i = 0; i < lowest.Count; i++) { if (lowest[i].Rank != lowestRank) { break; } reply += @" \c07{0}\c,".FormatWith(lowest[i].Name); } reply = reply.Substring(0, reply.Length - 1) + @" level \c07{0:rv}\c ranked \c07#{0:r}\c".FormatWith(lowest[0]); reply += @" \ufollowed by\u \c07{0:N}\c level \c07{0:rv}\c ranked \c07#{0:r}\c.".FormatWith(lowest[i]); await bc.SendReply(reply); } else { highest = p.Skills.Highest; long highestExp = highest[0].Exp; reply = @"\b{0}\b \uhighest\u skills:".FormatWith(rsn); for (i = 0; i < highest.Count; i++) { if (highest[i].Exp != highestExp) { break; } reply += @" \c07{0}\c,".FormatWith(highest[i].Name); } reply = reply.Substring(0, reply.Length - 1) + @" level \c07{0:rv}\c with \c07{0:e}\c exp.".FormatWith(highest[0]); reply += @" \ufollowed by\u \c07{0:N}\c level \c07{0:rv}\c with \c07{0:e}\c exp.".FormatWith(highest[i]); await bc.SendReply(reply); lowest = p.Skills.Lowest; long lowestExp = lowest[0].Exp; reply = @"\b{0}\b \ulowest\u skills:".FormatWith(rsn); for (i = 0; i < lowest.Count; i++) { if (lowest[i].Exp != lowestExp) { break; } reply += @" \c07{0}\c,".FormatWith(lowest[i].Name); } reply = reply.Substring(0, reply.Length - 1) + @" level \c07{0:rv}\c with \c07{0:e}\c exp.".FormatWith(lowest[0]); reply += @" \ufollowed by\u \c07{0:N}\c level \c07{0:rv}\c with \c07{0:e}\c exp.".FormatWith(lowest[i]); await bc.SendReply(reply); } }
public static async Task Record(CommandContext bc) { string rsn = await bc.GetPlayerName(bc.From.Nickname); string skill = Skill.OVER; if (bc.MessageTokens.Length > 1) { if (Skill.TryParse(bc.MessageTokens[1], ref skill)) { if (bc.MessageTokens.Length > 2) { rsn = await bc.GetPlayerName(bc.MessageTokens.Join(2)); } } else { rsn = await bc.GetPlayerName(bc.MessageTokens.Join(1)); } } try { string recordPage = new WebClient().DownloadString("http://runetracker.org/track-" + rsn + "," + Skill.NameToId(skill) + ",0"); string recordRegex = @"Exp Gain Records[^:]+:<\/b><br \/>\s+"; recordRegex += @"Day: <i>(?:<acronym title=""([^""]+)"">|)([^<]+)(?:<\/acronym>|)<\/i><br \/>\s+"; recordRegex += @"Week: <i>(?:<acronym title=""([^""]+)"">|)([^<]+)(?:<\/acronym>|)<\/i><br \/>\s+"; recordRegex += @"Month: <i>(?:<acronym title=""([^""]+)"">|)([^<]+)(?:<\/acronym>|)<\/i><br \/>"; Match M = Regex.Match(recordPage, recordRegex, RegexOptions.Singleline); if (M.Success) { await bc.SendReply(@"{0}'s records in {1}: Day \c07{2}\c ({3}); Week \c07{4}\c ({5}); Month \c07{6}\c ({7}); \c12http://runetracker.org/track-{0},{8},0\c", rsn, skill, M.Groups[2], string.IsNullOrEmpty(M.Groups[1].Value) ? "N/A" : M.Groups[1].Value, M.Groups[4], string.IsNullOrEmpty(M.Groups[3].Value) ? "N/A" : M.Groups[3].Value, M.Groups[6], string.IsNullOrEmpty(M.Groups[5].Value) ? "N/A" : M.Groups[5].Value, Skill.NameToId(skill)); } else { await bc.SendReply(@"rscript has no records in {0} for {1}.", skill, rsn); } return; } catch { } await bc.SendReply("rscript data source appears to be unreachable at the moment."); }
public static async Task CalcCombat(CommandContext bc) { if (bc.MessageTokens.Length == 1) { await bc.SendReply("Syntax: !CalcCombat Att Str Def Ran Mag"); return; } int Att, Str = 0, Def = 0, Ran = 0, Mag = 0; int.TryParse(bc.MessageTokens[1], out Att); if (bc.MessageTokens.Length > 2) { int.TryParse(bc.MessageTokens[2], out Str); } if (bc.MessageTokens.Length > 3) { int.TryParse(bc.MessageTokens[3], out Def); } if (bc.MessageTokens.Length > 4) { int.TryParse(bc.MessageTokens[4], out Ran); } if (bc.MessageTokens.Length > 5) { int.TryParse(bc.MessageTokens[5], out Mag); } var p = await Player.FromHiscores(await bc.GetPlayerName(bc.From.Nickname)); if (p.Ranked) { if (Att <= 0) { Att = p.Skills[Skill.ATTA].VLevel; } if (Str <= 0) { Str = p.Skills[Skill.STRE].VLevel; } if (Def <= 0) { Def = p.Skills[Skill.DEFE].VLevel; } if (Ran <= 0) { Ran = p.Skills[Skill.RANG].VLevel; } if (Mag <= 0) { Mag = p.Skills[Skill.MAGI].VLevel; } } else { if (Att <= 0) { Att = 1; } if (Str <= 0) { Str = 1; } if (Def <= 0) { Def = 1; } if (Ran <= 0) { Ran = 1; } if (Mag <= 0) { Mag = 1; } } string cmbclass = Utils.CombatClass(Att, Str, Ran, Mag); int cmblevel = Utils.CalculateCombat(Att, Str, Def, Ran, Mag); await bc.SendReply(@"Combat: \c07{0}\c | Class: \c07{1}\c | Stats: \c07{2} {3}\c {4} \c07{5} {6}\c", cmblevel, cmbclass, Att, Str, Def, Ran, Mag); int nextA = Utils.NextCombatAttack(Att, Str, Def, Ran, Mag); int nextS = Utils.NextCombatStrength(Att, Str, Def, Ran, Mag); int nextD = Utils.NextCombatDefence(Att, Str, Def, Ran, Mag); int nextR = Utils.NextCombatRanged(Att, Str, Def, Ran, Mag); int nextM = Utils.NextCombatMagic(Att, Str, Def, Ran, Mag); await bc.SendReply(@"Stats to level | Att: \c{0}\c | Str: \c{1}\c | Def: \c{2}\c | Range: \c{3}\c | Mage: \c{4}\c", (Att + nextA > 99 ? "04" : "03") + nextA, (Str + nextS > 99 ? "04" : "03") + nextS, (Def + nextD > 99 ? "04" : "03") + nextD, (Ran + nextR > 99 ? "04" : "03") + nextR, (Mag + nextM > 99 ? "04" : "03") + nextM); }
public static async Task Top(CommandContext bc) { string rsn; string skill = null, activity = null; int rank; // get @level bool level = false; if (bc.Message.Contains(" @level") || bc.Message.Contains(" @lvl") || bc.Message.Contains(" @l")) { level = true; bc.Message = bc.Message.Replace(" @level", string.Empty); bc.Message = bc.Message.Replace(" @lvl", string.Empty); bc.Message = bc.Message.Replace(" @l", string.Empty); } // Parse command arguments if (bc.MessageTokens.Length == 1) { // !Top rank = 1; skill = Skill.OVER; } else if (Bot.Activity.TryParse(bc.MessageTokens[1], ref activity) || Skill.TryParse(bc.MessageTokens[1], ref skill)) { // !Top Skill/Activity rank = 1; if (bc.MessageTokens.Length > 2) { if (int.TryParse(bc.MessageTokens[2], out rank)) { // !Top Skill/Activity Rank } else { // !Top Skill/Activity RSN rsn = await bc.GetPlayerName(bc.MessageTokens.Join(2)); var p = await Player.FromHiscores(rsn); if (p.Ranked) { if (skill == null) { rank = p.Activities[activity].Rank; } else { rank = p.Skills[skill].Rank; } } } } } else if (int.TryParse(bc.MessageTokens[1], out rank)) { // !Top Rank skill = Skill.OVER; } else { // !Top RSN rank = 1; skill = Skill.OVER; rsn = await bc.GetPlayerName(bc.MessageTokens.Join(1)); var p = await Player.FromHiscores(rsn); if (p.Ranked) { rank = p.Skills[skill].Rank; } } if (rank < 0) { rank = 1; } var hiscores = new Hiscores(skill, activity, rank); int startIndex = Math.Max(rank - hiscores[0].Rank - 5, 0); var reply = @"RS \u{0}\u rankings:".FormatWith(hiscores.Name.ToLowerInvariant()); if (activity == null) { for (int i = startIndex; i < Math.Min(startIndex + 12, hiscores.Count); i++) { reply += " "; if (hiscores[i].Rank == rank) { reply += @"\b"; } if (level) { reply += @"\c07#{0:r}\c {1} ({0:l})".FormatWith((Skill) hiscores[i], hiscores[i].RSN); } else { reply += @"\c07#{0:r}\c {1} ({0:e})".FormatWith((Skill) hiscores[i], hiscores[i].RSN); } if (hiscores[i].Rank == rank) { reply += @"\b"; } reply += ";"; } } else { for (int i = startIndex; i < Math.Min(12, hiscores.Count); i++) { reply += " "; if (hiscores[i].Rank == rank) { reply += @"\b"; } reply += @"\c07#{0}\c {1} ({2})".FormatWith(hiscores[i].Rank, hiscores[i].RSN, ((Activity) hiscores[i]).Score); if (hiscores[i].Rank == rank) { reply += @"\b"; } reply += ";"; } } await bc.SendReply(reply); }
public static async Task SkillInfo(CommandContext bc) { // get skill name string skillName = Skill.Parse(bc.MessageTokens[0]); // get goal string goal; Match M = Regex.Match(bc.Message, @"(?:#|goal=)(\d+|nl|nr|r\d+)"); if (M.Success) { goal = M.Groups[1].Value; bc.Message = Regex.Replace(bc.Message, @"(?:#|goal=)" + goal, string.Empty); bc.Message = Regex.Replace(bc.Message, @"\s+", " ").TrimEnd(); await Database.SetStringParameter("users", "goals", "fingerprint='" + bc.From.FingerPrint + "'", skillName, goal); } else { goal = await Database.GetStringParameter("users", "goals", "fingerprint='" + bc.From.FingerPrint + "'", skillName, "nl"); } // get item string item; M = Regex.Match(bc.Message, "(?:@|§)(.+)"); if (M.Success) { item = M.Groups[1].Value; bc.Message = Regex.Replace(bc.Message, "(?:@|§)" + item, string.Empty); bc.Message = Regex.Replace(bc.Message, @"\s+", " ").TrimEnd(); await Database.SetStringParameter("users", "items", "fingerprint='" + bc.From.FingerPrint + "'", skillName, item); } else { item = await Database.GetStringParameter("users", "items", "fingerprint='" + bc.From.FingerPrint + "'", skillName, null); } // get player var player = await Player.FromHiscores(await bc.GetPlayerName(bc.MessageTokens.Length > 1 ? bc.MessageTokens.Join(1) : bc.From.Nickname)); if (player.Ranked) { Skill skill = player.Skills[skillName]; // parse goal int targetLevel; long targetExp = 0; if (int.TryParse(goal, out targetLevel)) { // get level/exp if (targetLevel == 127) { targetLevel = 126; targetExp = 200000000; } else if (targetLevel > 127) { targetExp = Math.Min(200000000, targetLevel); targetLevel = targetExp.ToLevel(); } else { targetExp = targetLevel.ToExp(); } } else if (goal.StartsWithI("r")) { // get rank int goalrank; if (int.TryParse(goal.Substring(1), out goalrank)) { if (goalrank > 0 && goalrank < skill.Rank) { foreach (Skill h in new Hiscores(skill.Name, null, goalrank)) { if (h.Rank == goalrank) { targetExp = h.Exp; targetLevel = targetExp.ToLevel(); break; } } } } } else if (goal == "nr") { // get next rank if (skill.Rank > 1) { foreach (Skill h in new Hiscores(skill.Name, null, skill.Rank - 1)) { if (h.Rank == skill.Rank - 1) { targetExp = h.Exp; break; } } } else { targetExp = Math.Min(200000000, skill.Exp + 1); } targetLevel = targetExp.ToLevel(); } else { // next level if (skill.VLevel == 126) { targetLevel = 126; targetExp = 200000000; } else { targetLevel = skill.VLevel + 1; targetExp = targetLevel.ToExp(); } } if (targetExp < skill.Exp) { targetLevel = skill.VLevel + 1; targetExp = targetLevel.ToExp(); } // calculate % done long expToGo = 0; string percentDone; if (skill.Name == Skill.OVER) { long totalExp = 0, maxExp = 0; targetLevel = 0; foreach (Skill s in player.Skills.Values.Where(s => s.Name != Skill.OVER && s.Name != Skill.COMB)) { int maxSkillExp = s.MaxLevel.ToExp(); totalExp += Math.Min(maxSkillExp, s.Exp); maxExp += maxSkillExp; targetLevel += s.MaxLevel; } percentDone = Math.Round(totalExp / (double) maxExp * 100.0, 1).ToStringI(); item = null; } else { expToGo = targetExp - skill.Exp; percentDone = Math.Round(100 - expToGo / (double) (targetExp - skill.VLevel.ToExp()) * 100, 1).ToStringI(); } string reply = @"\b{0}\b \c07{1:n}\c | level: \c07{1:v}\c | exp: \c07{1:e}\c (\c07{2}%\c of {3}) | rank: \c07{1:R}\c".FormatWith(player.Name, skill, percentDone, targetLevel); // Add SS rank if applicable var ssPlayers = (await Players.FromClan("SS")).OrderBy(p => p.Skills[skill.Name]); var ssRank = ssPlayers.FindIndex(p => p.Name.EqualsI(player.Name)); if (ssRank != -1) { reply += @" (SS rank: \c07{0}\c)".FormatWith(ssRank + 1); } // Add exp to go and items if (expToGo > 0) { reply += @" | \c07{0:N0}\c exp. to go".FormatWith(expToGo); int speed = int.Parse(await Database.GetStringParameter("users", "speeds", "fingerprint='" + bc.From.FingerPrint + "'", skillName, "0"), CultureInfo.InvariantCulture); if (speed > 0) { reply += @" (\c07{0}\c)".FormatWith(TimeSpan.FromHours(expToGo / (double) speed).ToLongString()); } if (!string.IsNullOrEmpty(item)) { switch (item.ToUpperInvariant()) { case "LAMP": case "LAMPS": reply += @" (\c07{0:N0}\c lamps)".FormatWith(Utils.LampsToExp(skill.Exp, targetExp)); break; case "BOOK": case "BOOKS": reply += @" (\c07{0:N0}\c books)".FormatWith(Utils.BooksToExp(skill.Exp, targetExp)); break; case "EFFIGY": case "EFFIGIES": reply += @" (\c07{0:N0}\c effigies)".FormatWith(Utils.EffigyToExp(skill, targetExp)); break; case "SW": case "SOUL": case "SOULS": case "SOULWAR": case "SOULWARS": switch (skill.Name) { case Skill.ATTA: case Skill.STRE: case Skill.DEFE: case Skill.HITP: case Skill.RANG: case Skill.MAGI: case Skill.PRAY: case Skill.SLAY: reply += @" (\c07{0:N0}\c/\c07{1:N0}\c zeal)".FormatWith(Utils.SoulWarsZealToExp(skill.Name, skill.Exp, targetExp, false), Utils.SoulWarsZealToExp(skill.Name, skill.Exp, targetExp, true)); break; default: reply += " (unknown item)"; break; } break; case "PC": case "PEST": case "PESTCONTROL": switch (skill.Name) { case Skill.ATTA: case Skill.STRE: case Skill.DEFE: case Skill.HITP: case Skill.RANG: case Skill.MAGI: case Skill.PRAY: reply += @" (\c07{0:N0}\c/\c07{1:N0}\c/\c07{2:N0}\c points)".FormatWith(Utils.PestControlPointsToExp(skill.Name, skill.Exp, targetExp, 1), Utils.PestControlPointsToExp(skill.Name, skill.Exp, targetExp, 10), Utils.PestControlPointsToExp(skill.Name, skill.Exp, targetExp, 100)); break; default: reply += " (unknown item)"; break; } break; default: string item_name; int monster_hp; switch (skill.Name) { case Skill.ATTA: case Skill.DEFE: case Skill.STRE: case Skill.RANG: if (_GetMonster(item, out item_name, out monster_hp)) { reply += @" (\c07{0}\c {1})".FormatWith(Math.Ceiling(expToGo * 10d / monster_hp / 4d), item_name); } else { reply += " (unknown monster)"; } break; case Skill.HITP: if (_GetMonster(item, out item_name, out monster_hp)) { reply += @" (\c07{0}\c {1})".FormatWith(Math.Ceiling(expToGo * 30d / monster_hp / 4d), item_name); } else { reply += " (unknown monster)"; } break; case Skill.SLAY: if (_GetMonster(item, out item_name, out monster_hp)) { reply += @" (\c07{0}\c {1})".FormatWith(Math.Ceiling(expToGo * 10d / monster_hp), item_name); } else { reply += " (unknown monster)"; } break; default: try { double itemExp = item.ToInt32(); reply += @" (\c07{0} \citems to go.)".FormatWith(Math.Ceiling(expToGo / itemExp)); break; } catch { SkillItem itemFound = _GetItem(skill.Name, item); if (itemFound != null) { reply += @" (\c07{1}\c \c{0}{2}\c)".FormatWith(itemFound.IrcColour, Math.Ceiling(expToGo / itemFound.Exp), itemFound.Name); } else { reply += " (unknown item)"; } break; } } break; } } } await bc.SendReply(reply); // Show player performance if applicable DateTime lastupdate; var dblastupdate = await Database.LastUpdate(player.Name); if (dblastupdate == null || dblastupdate.Length < 8) { lastupdate = DateTime.UtcNow.AddHours(-DateTime.UtcNow.Hour + 6).AddMinutes(-DateTime.UtcNow.Minute).AddSeconds(-DateTime.UtcNow.Second); if (DateTime.UtcNow.Hour >= 0 && DateTime.UtcNow.Hour < 6) { lastupdate = lastupdate.AddDays(-1); } } else { lastupdate = dblastupdate.ToDateTime(); } string perf; reply = string.Empty; var p_old = await Player.FromDatabase(player.Name, lastupdate); if (!p_old.Ranked) { p_old = new Player(player.Name, (int) (DateTime.UtcNow - lastupdate).TotalSeconds); } if (p_old.Ranked) { perf = _GetPerformance("Today", p_old.Skills[skill.Name], skill); if (perf != null) { reply += perf + " | "; } } p_old = await Player.FromDatabase(player.Name, lastupdate.AddDays(-((int) lastupdate.DayOfWeek))); if (!p_old.Ranked) { p_old = new Player(player.Name, (int) (DateTime.UtcNow - lastupdate.AddDays(-((int) lastupdate.DayOfWeek))).TotalSeconds); } if (p_old.Ranked) { perf = _GetPerformance("Week", p_old.Skills[skill.Name], skill); if (perf != null) { reply += perf + " | "; } } p_old = await Player.FromDatabase(player.Name, lastupdate.AddDays(1 - lastupdate.Day)); if (!p_old.Ranked) { p_old = new Player(player.Name, (int) (DateTime.UtcNow - lastupdate.AddDays(1 - lastupdate.Day)).TotalSeconds); } if (p_old.Ranked) { perf = _GetPerformance("Month", p_old.Skills[skill.Name], skill); if (perf != null) { reply += perf + " | "; } } p_old = await Player.FromDatabase(player.Name, lastupdate.AddDays(1 - lastupdate.DayOfYear)); if (!p_old.Ranked) { p_old = new Player(player.Name, (int) (DateTime.UtcNow - lastupdate.AddDays(1 - lastupdate.DayOfYear)).TotalSeconds); } if (p_old.Ranked) { perf = _GetPerformance("Year", p_old.Skills[skill.Name], skill); if (perf != null) { reply += perf + " | "; } } // ***** start war ***** var warPlayer = await Database.FetchFirst("SELECT startrank,startlevel,startexp FROM warplayers WHERE channel=@channel AND rsn=@name", new MySqlParameter("@channel", bc.Channel), new MySqlParameter("@name", player.Name)); if (warPlayer != null && await Database.Lookup<string>("skill", "wars", "channel=@chan", new[] { new MySqlParameter("@chan", bc.Channel) }) == skill.Name) { var oldSkill = new Skill(skill.Name, warPlayer.GetInt32(0), warPlayer.GetInt32(1), warPlayer.GetInt32(2)); perf = _GetPerformance("War", oldSkill, skill); if (perf != null) { reply += perf; } } // ***** end war ***** if (reply.Length > 0) { await bc.SendReply(reply.EndsWithI(" | ") ? reply.Substring(0, reply.Length - 3) : reply); } return; } await bc.SendReply(@"\b{0}\b doesn't feature Hiscores.", player.Name); }