added z coords for portal discovery and minster disovery

This commit is contained in:
erik 2025-06-21 10:48:53 +02:00
parent 91cd934878
commit bb493febb4
7 changed files with 168 additions and 1573 deletions

View file

@ -108,6 +108,7 @@ namespace MosswartMassacre
CoreManager.Current.CharacterFilter.LoginComplete += CharacterFilter_LoginComplete;
CoreManager.Current.CharacterFilter.Death += OnCharacterDeath;
CoreManager.Current.WorldFilter.CreateObject += OnSpawn;
CoreManager.Current.WorldFilter.CreateObject += OnPortalDetected;
CoreManager.Current.WorldFilter.ReleaseObject += OnDespawn;
// Subscribe to inventory change events for taper tracking
CoreManager.Current.WorldFilter.CreateObject += OnInventoryCreate;
@ -172,6 +173,7 @@ namespace MosswartMassacre
CoreManager.Current.ChatBoxMessage -= new EventHandler<ChatTextInterceptEventArgs>(AllChatText);
CoreManager.Current.CharacterFilter.Death -= OnCharacterDeath;
CoreManager.Current.WorldFilter.CreateObject -= OnSpawn;
CoreManager.Current.WorldFilter.CreateObject -= OnPortalDetected;
CoreManager.Current.WorldFilter.ReleaseObject -= OnDespawn;
// Unsubscribe from inventory change events
CoreManager.Current.WorldFilter.CreateObject -= OnInventoryCreate;
@ -454,12 +456,51 @@ namespace MosswartMassacre
try
{
var coords = mob.Coordinates();
// Get DECAL coordinates
var decalCoords = mob.Coordinates();
if (decalCoords == null) return;
const string fmt = "F7";
string ns = coords.NorthSouth.ToString(fmt, CultureInfo.InvariantCulture);
string ew = coords.EastWest.ToString(fmt, CultureInfo.InvariantCulture);
string ns = decalCoords.NorthSouth.ToString(fmt, CultureInfo.InvariantCulture);
string ew = decalCoords.EastWest.ToString(fmt, CultureInfo.InvariantCulture);
await WebSocket.SendSpawnAsync(ns, ew, mob.Name);
// Get Z coordinate using RawCoordinates() for accurate world Z position
string zCoord = "0";
try
{
var rawCoords = mob.RawCoordinates();
if (rawCoords != null)
{
zCoord = rawCoords.Z.ToString("F2", CultureInfo.InvariantCulture);
}
else
{
// Fallback to player Z approximation if RawCoordinates fails
var playerCoords = Coordinates.Me;
if (Math.Abs(playerCoords.Z) > 0.1)
{
zCoord = playerCoords.Z.ToString("F2", CultureInfo.InvariantCulture);
}
}
}
catch
{
// Fallback to player Z approximation on error
try
{
var playerCoords = Coordinates.Me;
if (Math.Abs(playerCoords.Z) > 0.1)
{
zCoord = playerCoords.Z.ToString("F2", CultureInfo.InvariantCulture);
}
}
catch
{
zCoord = "0";
}
}
await WebSocket.SendSpawnAsync(ns, ew, zCoord, mob.Name);
}
catch (Exception ex)
{
@ -467,6 +508,66 @@ namespace MosswartMassacre
}
}
private async void OnPortalDetected(object sender, CreateObjectEventArgs e)
{
var portal = e.New;
if (portal.ObjectClass != ObjectClass.Portal) return;
try
{
// Get portal coordinates from DECAL
var decalCoords = portal.Coordinates();
if (decalCoords == null) return;
const string fmt = "F7";
string ns = decalCoords.NorthSouth.ToString(fmt, CultureInfo.InvariantCulture);
string ew = decalCoords.EastWest.ToString(fmt, CultureInfo.InvariantCulture);
// Get Z coordinate using RawCoordinates() for accurate world Z position
string zCoord = "0";
try
{
var rawCoords = portal.RawCoordinates();
if (rawCoords != null)
{
zCoord = rawCoords.Z.ToString("F2", CultureInfo.InvariantCulture);
}
else
{
// Fallback to player Z approximation if RawCoordinates fails
var playerCoords = Coordinates.Me;
if (Math.Abs(playerCoords.Z) > 0.1)
{
zCoord = playerCoords.Z.ToString("F2", CultureInfo.InvariantCulture);
}
}
}
catch
{
// Fallback to player Z approximation on error
try
{
var playerCoords = Coordinates.Me;
if (Math.Abs(playerCoords.Z) > 0.1)
{
zCoord = playerCoords.Z.ToString("F2", CultureInfo.InvariantCulture);
}
}
catch
{
zCoord = "0";
}
}
await WebSocket.SendPortalAsync(ns, ew, zCoord, portal.Name);
}
catch (Exception ex)
{
PluginCore.WriteToChat($"[PORTAL ERROR] {ex.Message}");
PluginCore.WriteToChat($"[WS] Portal send failed: {ex}");
}
}
private void OnDespawn(object sender, ReleaseObjectEventArgs e)
{
@ -775,12 +876,12 @@ namespace MosswartMassacre
rareTextOnly = null;
// Match pattern: "<name> has discovered the <something>!"
string pattern = @"^(?<name>['A-Za-z ]+)\s(?<text>has discovered the .*!$)";
string pattern = @"^(?<name>['A-Za-z ]+)\shas discovered the (?<item>.*?)!$";
Match match = Regex.Match(text, pattern);
if (match.Success && match.Groups["name"].Value == CoreManager.Current.CharacterFilter.Name)
{
rareTextOnly = match.Groups["text"].Value; // just "has discovered the Ancient Pickle!"
rareTextOnly = match.Groups["item"].Value; // just "Ancient Pickle"
return true;
}

View file

@ -41,6 +41,29 @@ namespace MosswartMassacre
}
}
/// <summary>
/// Return any WorldObject's raw world position by reading the
/// physics-object pointer (same offsets: +0x84/88/8C).
/// </summary>
public static unsafe Vector3 GetWorldObjectPosition(int objectId)
{
try
{
if (!CoreManager.Current.Actions.IsValidObject(objectId))
return new Vector3();
byte* p = (byte*)CoreManager.Current.Actions.Underlying.GetPhysicsObjectPtr(objectId);
return new Vector3(
*(float*)(p + 0x84), // X
*(float*)(p + 0x88), // Y
*(float*)(p + 0x8C)); // Z
}
catch
{
return new Vector3();
}
}
/// <summary>
/// Convenience: returns the current landcell (upper 16 bits of landblock).
/// </summary>
@ -65,6 +88,26 @@ namespace MosswartMassacre
return new Coordinates(ew, ns, pos.Z);
}
/// <summary>
/// Get AC-style coordinates (EW/NS/Z) for any WorldObject.
/// </summary>
public static Coordinates GetWorldObjectCoordinates(WorldObject wo)
{
if (wo == null) return new Coordinates();
Vector3 pos = GetWorldObjectPosition(wo.Id);
// Get landcell from the object's coordinates
var coordsObj = wo.Coordinates();
if (coordsObj == null) return new Coordinates();
// Convert DECAL coords to our Coordinates with Z
double ew = coordsObj.EastWest;
double ns = coordsObj.NorthSouth;
return new Coordinates(ew, ns, pos.Z);
}
/* ----------------------------------------------------------
* 3) Generic math helpers you may want later
* -------------------------------------------------------- */

View file

@ -226,7 +226,7 @@ namespace MosswartMassacre
var json = JsonConvert.SerializeObject(envelope);
await SendEncodedAsync(json, CancellationToken.None);
}
public static async Task SendSpawnAsync(string nsCoord, string ewCoord, string monster)
public static async Task SendSpawnAsync(string nsCoord, string ewCoord, string zCoord, string monster)
{
var envelope = new
{
@ -235,8 +235,24 @@ namespace MosswartMassacre
character_name = CoreManager.Current.CharacterFilter.Name,
mob = monster,
ns = nsCoord,
ew = ewCoord
ew = ewCoord,
z = zCoord
};
var json = JsonConvert.SerializeObject(envelope);
await SendEncodedAsync(json, CancellationToken.None);
}
public static async Task SendPortalAsync(string nsCoord, string ewCoord, string zCoord, string portalName)
{
var envelope = new
{
type = "portal",
timestamp = DateTime.UtcNow.ToString("o"),
character_name = CoreManager.Current.CharacterFilter.Name,
portal_name = portalName,
ns = nsCoord,
ew = ewCoord,
z = zCoord
};
var json = JsonConvert.SerializeObject(envelope);
await SendEncodedAsync(json, CancellationToken.None);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 MiB

File diff suppressed because it is too large Load diff

View file

@ -1,110 +0,0 @@
local libQuest = {
List = {},
Dictionary = {}
}
---@class Quest: Object
---@field id number
---@field solves number
---@field timestamp number
---@field description string
---@field maxsolves number
---@field delta number
---@field expiretime number
local function OnChatText(evt)
local taskname, solves, timestamp, description, maxsolves, delta = string.match(evt.Message, "([%w%s%(%)-]+) %- (%d+) solves %((%d+)%)\"([^\"]+)\" (%-?%d+) (%d+)")
if taskname and solves and timestamp and description and maxsolves and delta then
table.insert(libQuest.List, {id=taskname,solves=solves,timestamp=timestamp,description=description,maxsolves=maxsolves,delta=delta,expiretime=timestamp+delta})
libQuest.Dictionary[taskname] = {id=taskname,solves=solves,timestamp=timestamp,description=description,maxsolves=maxsolves,delta=delta,expiretime=timestamp+delta}
end
end
function libQuest:Clear()
self.List = {}
self.Dictionary = {}
end
function libQuest:Refresh()
self:Clear()
game.OnTick.Once(function (evt)
game.World.OnChatText.Add(OnChatText)
sleep(100)
game.Actions.InvokeChat("/myquests")
sleep(3000)
game.World.OnChatText.Remove(OnChatText)
end)
end
function libQuest:IsQuestAvailable(queststamp)
local quest = self.Dictionary[queststamp]
if quest == nil then return true end
return quest.expiretime < os.time()
end
function libQuest:IsQuestMaxSolved(queststamp)
local quest = self.Dictionary[queststamp]
if quest == nil then return false end
if tonumber(quest.maxsolves) == tonumber(quest.solves) then return true end
return false
end
function libQuest:HasQuestFlag(queststamp)
local quest = self.Dictionary[queststamp]
return quest ~= nil
end
function libQuest:GetFieldByID(quest, id)
local fields = {
quest.id,
quest.solves,
quest.timestamp,
quest.maxsolves,
quest.delta,
quest.expiretime
}
return fields[id] or quest.id
end
function libQuest:FormatTimeStamp(time)
return tostring(os.date("%m/%d/%Y %H:%M:%S", time))
end
function libQuest:FormatSeconds(seconds)
if seconds <= 0 then
return "0s"
end
local days = math.floor(seconds / 86400)
seconds = seconds % 86400
local hours = math.floor(seconds / 3600)
seconds = seconds % 3600
local minutes = math.floor(seconds / 60)
seconds = math.floor(seconds % 60)
local result = ""
if days > 0 then
result = result .. days .. "d "
end
if hours > 0 then
result = result .. hours .. "h "
end
if minutes > 0 then
result = result .. minutes .. "m "
end
if seconds > 0 or result == "" then
result = result .. seconds .. "s"
end
return result:match("^%s*(.-)%s*$") -- Trim any trailing space
end
function libQuest:GetTimeUntilExpire(quest)
if quest == nil then return "Unknown" end
local expireTime = self:FormatSeconds(quest.expiretime - os.time())
if expireTime == "0s" then
return "Ready"
end
return expireTime
end
return libQuest

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 MiB