added z coords for portal discovery and minster disovery
This commit is contained in:
parent
91cd934878
commit
bb493febb4
7 changed files with 168 additions and 1573 deletions
|
|
@ -108,6 +108,7 @@ namespace MosswartMassacre
|
||||||
CoreManager.Current.CharacterFilter.LoginComplete += CharacterFilter_LoginComplete;
|
CoreManager.Current.CharacterFilter.LoginComplete += CharacterFilter_LoginComplete;
|
||||||
CoreManager.Current.CharacterFilter.Death += OnCharacterDeath;
|
CoreManager.Current.CharacterFilter.Death += OnCharacterDeath;
|
||||||
CoreManager.Current.WorldFilter.CreateObject += OnSpawn;
|
CoreManager.Current.WorldFilter.CreateObject += OnSpawn;
|
||||||
|
CoreManager.Current.WorldFilter.CreateObject += OnPortalDetected;
|
||||||
CoreManager.Current.WorldFilter.ReleaseObject += OnDespawn;
|
CoreManager.Current.WorldFilter.ReleaseObject += OnDespawn;
|
||||||
// Subscribe to inventory change events for taper tracking
|
// Subscribe to inventory change events for taper tracking
|
||||||
CoreManager.Current.WorldFilter.CreateObject += OnInventoryCreate;
|
CoreManager.Current.WorldFilter.CreateObject += OnInventoryCreate;
|
||||||
|
|
@ -172,6 +173,7 @@ namespace MosswartMassacre
|
||||||
CoreManager.Current.ChatBoxMessage -= new EventHandler<ChatTextInterceptEventArgs>(AllChatText);
|
CoreManager.Current.ChatBoxMessage -= new EventHandler<ChatTextInterceptEventArgs>(AllChatText);
|
||||||
CoreManager.Current.CharacterFilter.Death -= OnCharacterDeath;
|
CoreManager.Current.CharacterFilter.Death -= OnCharacterDeath;
|
||||||
CoreManager.Current.WorldFilter.CreateObject -= OnSpawn;
|
CoreManager.Current.WorldFilter.CreateObject -= OnSpawn;
|
||||||
|
CoreManager.Current.WorldFilter.CreateObject -= OnPortalDetected;
|
||||||
CoreManager.Current.WorldFilter.ReleaseObject -= OnDespawn;
|
CoreManager.Current.WorldFilter.ReleaseObject -= OnDespawn;
|
||||||
// Unsubscribe from inventory change events
|
// Unsubscribe from inventory change events
|
||||||
CoreManager.Current.WorldFilter.CreateObject -= OnInventoryCreate;
|
CoreManager.Current.WorldFilter.CreateObject -= OnInventoryCreate;
|
||||||
|
|
@ -454,12 +456,51 @@ namespace MosswartMassacre
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var coords = mob.Coordinates();
|
// Get DECAL coordinates
|
||||||
|
var decalCoords = mob.Coordinates();
|
||||||
|
if (decalCoords == null) return;
|
||||||
|
|
||||||
const string fmt = "F7";
|
const string fmt = "F7";
|
||||||
string ns = coords.NorthSouth.ToString(fmt, CultureInfo.InvariantCulture);
|
string ns = decalCoords.NorthSouth.ToString(fmt, CultureInfo.InvariantCulture);
|
||||||
string ew = coords.EastWest.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)
|
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)
|
private void OnDespawn(object sender, ReleaseObjectEventArgs e)
|
||||||
{
|
{
|
||||||
|
|
@ -775,12 +876,12 @@ namespace MosswartMassacre
|
||||||
rareTextOnly = null;
|
rareTextOnly = null;
|
||||||
|
|
||||||
// Match pattern: "<name> has discovered the <something>!"
|
// 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);
|
Match match = Regex.Match(text, pattern);
|
||||||
|
|
||||||
if (match.Success && match.Groups["name"].Value == CoreManager.Current.CharacterFilter.Name)
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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>
|
/// <summary>
|
||||||
/// Convenience: returns the current landcell (upper 16 bits of landblock).
|
/// Convenience: returns the current landcell (upper 16 bits of landblock).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -65,6 +88,26 @@ namespace MosswartMassacre
|
||||||
return new Coordinates(ew, ns, pos.Z);
|
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
|
* 3) Generic math helpers you may want later
|
||||||
* -------------------------------------------------------- */
|
* -------------------------------------------------------- */
|
||||||
|
|
|
||||||
|
|
@ -226,7 +226,7 @@ namespace MosswartMassacre
|
||||||
var json = JsonConvert.SerializeObject(envelope);
|
var json = JsonConvert.SerializeObject(envelope);
|
||||||
await SendEncodedAsync(json, CancellationToken.None);
|
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
|
var envelope = new
|
||||||
{
|
{
|
||||||
|
|
@ -235,8 +235,24 @@ namespace MosswartMassacre
|
||||||
character_name = CoreManager.Current.CharacterFilter.Name,
|
character_name = CoreManager.Current.CharacterFilter.Name,
|
||||||
mob = monster,
|
mob = monster,
|
||||||
ns = nsCoord,
|
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);
|
var json = JsonConvert.SerializeObject(envelope);
|
||||||
await SendEncodedAsync(json, CancellationToken.None);
|
await SendEncodedAsync(json, CancellationToken.None);
|
||||||
|
|
|
||||||
BIN
dereth.png
BIN
dereth.png
Binary file not shown.
|
Before Width: | Height: | Size: 5.6 MiB |
File diff suppressed because it is too large
Load diff
|
|
@ -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 |
Loading…
Add table
Add a link
Reference in a new issue