MosswartMassacre/MosswartMassacre/QuestManager.cs
2025-06-08 00:15:55 +02:00

296 lines
No EOL
9.1 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Decal.Adapter;
using Decal.Adapter.Wrappers;
namespace MosswartMassacre
{
/// <summary>
/// Quest tracking and management system
/// Ported from UBS Lua quest system
/// </summary>
public class QuestManager : IDisposable
{
#region Quest Data Structures
public class Quest
{
public string Id { get; set; }
public int Solves { get; set; }
public int Timestamp { get; set; }
public string Description { get; set; }
public int MaxSolves { get; set; }
public int Delta { get; set; }
public int ExpireTime { get; set; }
}
#endregion
#region Properties
public List<Quest> QuestList { get; private set; }
public Dictionary<string, Quest> QuestDictionary { get; private set; }
#endregion
#region Events and State
private bool isRefreshing = false;
private DateTime lastRefreshTime = DateTime.MinValue;
#endregion
public QuestManager()
{
QuestList = new List<Quest>();
QuestDictionary = new Dictionary<string, Quest>();
// Hook into chat events for quest parsing
InitializeChatHooks();
}
#region Initialization
private void InitializeChatHooks()
{
try
{
if (CoreManager.Current != null)
{
CoreManager.Current.ChatBoxMessage += OnChatBoxMessage;
}
}
catch (Exception ex)
{
PluginCore.WriteToChat($"Error initializing quest chat hooks: {ex.Message}");
}
}
#endregion
#region Quest Parsing
private void OnChatBoxMessage(object sender, ChatTextInterceptEventArgs e)
{
try
{
if (!isRefreshing || string.IsNullOrEmpty(e.Text))
return;
// Parse quest information from /myquests output
ParseQuestLine(e.Text);
}
catch (Exception ex)
{
PluginCore.WriteToChat($"Error parsing quest line: {ex.Message}");
}
}
private void ParseQuestLine(string text)
{
try
{
// Quest line format: TaskName - Solves solves (Timestamp)"Description" MaxSolves Delta
// Example: "SomeQuest - 5 solves (1640995200)"Quest description here" 10 3600
var pattern = @"([^\-]+) - (\d+) solves \((\d+)\)""([^""]+)"" (-?\d+) (\d+)";
var match = Regex.Match(text, pattern);
if (match.Success)
{
var quest = new Quest
{
Id = match.Groups[1].Value.Trim(),
Solves = int.Parse(match.Groups[2].Value),
Timestamp = int.Parse(match.Groups[3].Value),
Description = match.Groups[4].Value,
MaxSolves = int.Parse(match.Groups[5].Value),
Delta = int.Parse(match.Groups[6].Value)
};
quest.ExpireTime = quest.Timestamp + quest.Delta;
// Add to collections
QuestList.Add(quest);
QuestDictionary[quest.Id] = quest;
}
}
catch (Exception ex)
{
PluginCore.WriteToChat($"Error parsing quest line '{text}': {ex.Message}");
}
}
#endregion
#region Quest Management
public void RefreshQuests()
{
try
{
if (isRefreshing)
return;
ClearQuests();
isRefreshing = true;
// Issue /myquests command to refresh quest data
CoreManager.Current.Actions.InvokeChatParser("/myquests");
// Stop listening after a delay
System.Threading.Timer stopTimer = null;
stopTimer = new System.Threading.Timer(_ =>
{
isRefreshing = false;
stopTimer?.Dispose();
lastRefreshTime = DateTime.Now;
}, null, 3000, System.Threading.Timeout.Infinite);
}
catch (Exception ex)
{
isRefreshing = false;
PluginCore.WriteToChat($"Error refreshing quests: {ex.Message}");
}
}
public void ClearQuests()
{
QuestList.Clear();
QuestDictionary.Clear();
}
public bool IsQuestAvailable(string questStamp)
{
if (!QuestDictionary.TryGetValue(questStamp, out Quest quest))
return true; // If quest not found, assume available
var currentTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
return quest.ExpireTime < currentTime;
}
public bool IsQuestMaxSolved(string questStamp)
{
if (!QuestDictionary.TryGetValue(questStamp, out Quest quest))
return false;
return quest.Solves >= quest.MaxSolves;
}
public bool HasQuestFlag(string questStamp)
{
return QuestDictionary.ContainsKey(questStamp);
}
public string GetTimeUntilExpire(Quest quest)
{
if (quest == null)
return "Unknown";
var currentTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
var timeLeft = quest.ExpireTime - currentTime;
if (timeLeft <= 0)
return "Ready";
return FormatSeconds((int)timeLeft);
}
public string FormatTimeStamp(int timestamp)
{
try
{
var dateTime = DateTimeOffset.FromUnixTimeSeconds(timestamp).DateTime;
return dateTime.ToString("MM/dd/yyyy HH:mm:ss");
}
catch
{
return "Invalid";
}
}
public string FormatSeconds(int seconds)
{
if (seconds <= 0)
return "0s";
var days = seconds / 86400;
seconds %= 86400;
var hours = seconds / 3600;
seconds %= 3600;
var minutes = seconds / 60;
seconds %= 60;
var result = "";
if (days > 0) result += $"{days}d ";
if (hours > 0) result += $"{hours}h ";
if (minutes > 0) result += $"{minutes}m ";
if (seconds > 0 || string.IsNullOrEmpty(result)) result += $"{seconds}s";
return result.Trim();
}
public object GetFieldByID(Quest quest, int id)
{
if (quest == null)
return null;
switch (id)
{
case 1: return quest.Id;
case 2: return quest.Solves;
case 3: return quest.Timestamp;
case 4: return quest.MaxSolves;
case 5: return quest.Delta;
case 6: return quest.ExpireTime;
default: return quest.Id;
}
}
#endregion
#region Society Quest Helpers
public string GetSocietyName(int factionBits)
{
switch (factionBits)
{
case 1: return "Celestial Hand";
case 2: return "Eldrytch Web";
case 4: return "Radiant Blood";
default: return "Unknown";
}
}
public string GetSocietyRank(int ribbons)
{
if (ribbons >= 1001) return "Master";
if (ribbons >= 601) return "Lord";
if (ribbons >= 301) return "Knight";
if (ribbons >= 101) return "Adept";
if (ribbons >= 1) return "Initiate";
return "None";
}
public int GetMaxRibbonsPerDay(string rank)
{
switch (rank)
{
case "Initiate": return 50;
case "Adept": return 100;
case "Knight": return 150;
case "Lord": return 200;
case "Master": return 250;
default: return 0;
}
}
#endregion
#region Cleanup
public void Dispose()
{
try
{
if (CoreManager.Current != null)
{
CoreManager.Current.ChatBoxMessage -= OnChatBoxMessage;
}
ClearQuests();
}
catch (Exception ex)
{
PluginCore.WriteToChat($"Error disposing quest manager: {ex.Message}");
}
}
#endregion
}
}