xabbo-scripts/Scripts/Autogate.csx
Administrator 7a548130a3 Move all scripts into Scripts/ subfolder
Keeps the repo root clean - only README.md visible on landing page.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 09:49:37 +01:00

156 lines
5.7 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
public struct Point : IEquatable<Point>
{
public int X { get; }
public int Y { get; }
public Point(int x, int y) { X = x; Y = y; }
public static implicit operator Point((int x, int y) tuple) => new Point(tuple.x, tuple.y);
public bool Equals(Point other) => X == other.X && Y == other.Y;
public override bool Equals(object obj) => obj is Point other && Equals(other);
public override int GetHashCode() => HashCode.Combine(X, Y);
public static bool operator ==(Point left, Point right) => left.Equals(right);
public static bool operator !=(Point left, Point right) => !(left == right);
public override string ToString() => $"({X},{Y})";
}
Log("started");
const string FURNI_NAME_CONTAINS_TEXT = "One Way Gate";
Regex mvRegex = new Regex(@"/mv (\d+),(\d+),([\d\.]+)/");
void CheckAndEnterGateGeneral(int userTileX, int userTileY)
{
if (FloorItems == null) return;
foreach (var item in FloorItems)
{
if (item == null || item.Location == null) continue;
string itemName = null;
try { itemName = item.GetName(); } catch { continue; }
if (itemName != null && itemName.Contains(FURNI_NAME_CONTAINS_TEXT))
{
int gateX = item.Location.X;
int gateY = item.Location.Y;
int gateDir = item.Direction;
long gateId = item.Id;
bool shouldEnter = false;
if (gateDir == 0) { if (userTileX == gateX && userTileY == gateY - 1) shouldEnter = true; }
else if (gateDir == 2) { if (userTileX == gateX + 1 && userTileY == gateY) shouldEnter = true; }
else if (gateDir == 4) { if (userTileX == gateX && userTileY == gateY + 1) shouldEnter = true; }
else if (gateDir == 6) { if (userTileX == gateX - 1 && userTileY == gateY) shouldEnter = true; }
if (shouldEnter)
{
Log($"User tile ({userTileX},{userTileY}) matches criteria for Gate (ID {gateId}, Name: '{itemName}') at ({gateX},{gateY} Dir:{gateDir}) via GeneralCheck. Sending packet.");
Send(Out.EnterOneWayDoor, gateId);
return;
}
}
}
}
void HandleUserUpdate(dynamic e)
{
if (Self == null) return;
var packet = e.Packet;
int numUpdates = packet.ReadInt();
for (int i = 0; i < numUpdates; i++)
{
int entityIndex = packet.ReadInt();
int currentX = packet.ReadInt();
int currentY = packet.ReadInt();
packet.ReadString();
packet.ReadInt();
packet.ReadInt();
string action = packet.ReadString();
if (entityIndex == Self.Index)
{
Point tileToConsiderForGate;
Match match = mvRegex.Match(action);
if (match.Success)
{
try
{
int targetX = int.Parse(match.Groups[1].Value);
int targetY = int.Parse(match.Groups[2].Value);
tileToConsiderForGate = new Point(targetX, targetY);
}
catch { tileToConsiderForGate = new Point(currentX, currentY); }
}
else { tileToConsiderForGate = new Point(currentX, currentY); }
CheckAndEnterGateGeneral(tileToConsiderForGate.X, tileToConsiderForGate.Y);
}
}
}
void HandleObjectUpdate(dynamic e)
{
if (Self == null || Self.Location == null) return;
var packet = e.Packet;
int furniIdFromPacket = packet.ReadInt();
packet.ReadInt();
int itemXFromPacket = packet.ReadInt();
int itemYFromPacket = packet.ReadInt();
int itemNewDirectionFromPacket = packet.ReadInt();
var itemInstance = FloorItems?.FirstOrDefault(f => f != null && f.Id == furniIdFromPacket);
if (itemInstance != null)
{
string itemName = null;
try { itemName = itemInstance.GetName(); } catch { return; }
if (itemName != null && itemName.Contains(FURNI_NAME_CONTAINS_TEXT))
{
bool shouldEnter = false;
int userX = Self.Location.X;
int userY = Self.Location.Y;
if (itemNewDirectionFromPacket == 0) { if (userX == itemXFromPacket && userY == itemYFromPacket - 1) shouldEnter = true; }
else if (itemNewDirectionFromPacket == 2) { if (userX == itemXFromPacket + 1 && userY == itemYFromPacket) shouldEnter = true; }
else if (itemNewDirectionFromPacket == 4) { if (userX == itemXFromPacket && userY == itemYFromPacket + 1) shouldEnter = true; }
else if (itemNewDirectionFromPacket == 6) { if (userX == itemXFromPacket - 1 && userY == itemYFromPacket) shouldEnter = true; }
if (shouldEnter)
{
Log($"User at ({userX},{userY}) matches criteria for Gate ID {furniIdFromPacket} ({itemXFromPacket},{itemYFromPacket}) with NewDir:{itemNewDirectionFromPacket} from ObjectUpdate. Sending packet.");
Send(Out.EnterOneWayDoor, furniIdFromPacket);
}
}
}
}
void InitializeStateAndCheckGates(dynamic eventArgs)
{
if (Self != null && Self.Location != null)
{
Point initialPosition = new Point(Self.Location.X, Self.Location.Y);
CheckAndEnterGateGeneral(initialPosition.X, initialPosition.Y);
}
}
OnIntercept(In["UserUpdate"], e => HandleUserUpdate(e));
OnIntercept(In["ObjectUpdate"], e => HandleObjectUpdate(e));
OnEnteredRoom(e => InitializeStateAndCheckGates(e));
if (Self != null && Self.Location != null) {
InitializeStateAndCheckGates(null);
}
while(Run)
{
try { }
catch (Exception ex) { Log($"MAIN LOOP ERROR: {ex.GetType().Name} - {ex.Message}"); }
if (!Run) break;
Delay(30);
}
Log("closed");