Added scripts from C:\Users\ploet\Desktop\Habbo\Xabbo Scripte: - 39 KI/Chatbot scripts (ChatGPT, Gemini, Grok, DeepSeek, Ollama) - Game solvers (Domino, Dodgeball, Obsidian Maze, IceBall) - Collision avoidance bots (5 versions) - Plant/breeding automation (12 scripts) - Trading tools, packet debuggers, room utilities - Navigation & teleport helpers Removed: 9 files (3 empty, 2 trivial, 4 cross-duplicates) Updated README with full categorized index of all 230+ scripts. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
547 lines
14 KiB
C#
547 lines
14 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Globalization;
|
|
|
|
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})";
|
|
}
|
|
|
|
public class Tile
|
|
{
|
|
public int X { get; set; }
|
|
public int Y { get; set; }
|
|
public double Z { get; set; }
|
|
public Point XY => new Point(X, Y);
|
|
public Tile(int x, int y, double z = 0.0) { X = x; Y = y; Z = z; }
|
|
}
|
|
|
|
public class Duck
|
|
{
|
|
public long id { get; set; }
|
|
public Point pos { get; set; }
|
|
public Point lastpos { get; set; }
|
|
public Point vel { get; set; }
|
|
public DateTime lastseen { get; set; }
|
|
public Queue<Point> trail { get; set; } = new Queue<Point>(10);
|
|
public double spd { get; set; }
|
|
}
|
|
|
|
HashSet<Point> tiles = new HashSet<Point>();
|
|
Dictionary<Point, List<Point>> adj = new Dictionary<Point, List<Point>>();
|
|
Point[] dirs = { (0,1), (0,-1), (1,0), (-1,0), (1,1), (1,-1), (-1,1), (-1,-1) };
|
|
|
|
Dictionary<long, Duck> ducks = new Dictionary<long, Duck>();
|
|
Tile tgt = null;
|
|
Point lastcmd = default(Point);
|
|
DateTime cmdtime = DateTime.MinValue;
|
|
Point prev = default(Point);
|
|
Point curr = default(Point);
|
|
Queue<Point> hist = new Queue<Point>(5);
|
|
int stuck = 0;
|
|
HashSet<Point> danger = new HashSet<Point>();
|
|
|
|
Point dest = default(Point);
|
|
bool forcedest = false;
|
|
DateTime desttime = DateTime.MinValue;
|
|
|
|
bool floorPlanParsed = false;
|
|
|
|
void ParseFloorPlan()
|
|
{
|
|
if (floorPlanParsed) return;
|
|
|
|
try
|
|
{
|
|
dynamic floorPlan = FloorPlan;
|
|
if (floorPlan == null) return;
|
|
|
|
int width = floorPlan.Width;
|
|
int length = floorPlan.Length;
|
|
|
|
tiles.Clear();
|
|
|
|
IReadOnlyList<int> tilesData = null;
|
|
string heightmapString = null;
|
|
|
|
try { tilesData = floorPlan.Tiles; } catch { }
|
|
try { heightmapString = floorPlan.Heightmap; } catch { }
|
|
|
|
if (heightmapString != null)
|
|
{
|
|
heightmapString = heightmapString.Replace("\r", "").Replace("\n", "");
|
|
for (int y = 0; y < length; y++)
|
|
{
|
|
for (int x = 0; x < width; x++)
|
|
{
|
|
if (heightmapString[y * width + x] != 'x')
|
|
{
|
|
tiles.Add(new Point(x, y));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (tilesData != null)
|
|
{
|
|
for (int y = 0; y < length; y++)
|
|
{
|
|
for (int x = 0; x < width; x++)
|
|
{
|
|
int tileIndex = y * width + x;
|
|
if (tileIndex < tilesData.Count && tilesData[tileIndex] >= 0 && tilesData[tileIndex] < 250)
|
|
{
|
|
tiles.Add(new Point(x, y));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
BuildAdjacencyMap();
|
|
floorPlanParsed = true;
|
|
}
|
|
catch { }
|
|
}
|
|
|
|
void BuildAdjacencyMap()
|
|
{
|
|
adj.Clear();
|
|
|
|
foreach(var t in tiles)
|
|
{
|
|
var n = new List<Point>();
|
|
foreach(var d in dirs)
|
|
{
|
|
Point p = new Point(t.X + d.X, t.Y + d.Y);
|
|
if(tiles.Contains(p)) n.Add(p);
|
|
}
|
|
adj[t] = n;
|
|
}
|
|
}
|
|
|
|
Point getpos()
|
|
{
|
|
if (Self == null) return default(Point);
|
|
if (tgt != null) return tgt.XY;
|
|
if (!lastcmd.Equals(default(Point)) && (DateTime.UtcNow - cmdtime).TotalMilliseconds < 250)
|
|
return lastcmd;
|
|
if (Self.Location != null) return new Point(Self.Location.X, Self.Location.Y);
|
|
return default(Point);
|
|
}
|
|
|
|
void go(int x, int y)
|
|
{
|
|
Move(x, y);
|
|
lastcmd = new Point(x, y);
|
|
cmdtime = DateTime.UtcNow;
|
|
tgt = null;
|
|
}
|
|
|
|
HashSet<Point> predict(int frames)
|
|
{
|
|
var zones = new HashSet<Point>();
|
|
|
|
foreach(var d in ducks.Values)
|
|
{
|
|
zones.Add(d.pos);
|
|
|
|
if(!d.vel.Equals(default(Point)))
|
|
{
|
|
for(int i = 1; i <= frames; i++)
|
|
{
|
|
Point pred = new Point(
|
|
d.pos.X + d.vel.X * i,
|
|
d.pos.Y + d.vel.Y * i
|
|
);
|
|
if(tiles.Contains(pred))
|
|
zones.Add(pred);
|
|
}
|
|
}
|
|
|
|
if(frames >= 1 && adj.ContainsKey(d.pos))
|
|
{
|
|
foreach(var n in adj[d.pos])
|
|
zones.Add(n);
|
|
}
|
|
|
|
if(frames >= 2)
|
|
{
|
|
foreach(var d1 in dirs)
|
|
{
|
|
Point p1 = new Point(d.pos.X + d1.X, d.pos.Y + d1.Y);
|
|
if(tiles.Contains(p1))
|
|
{
|
|
zones.Add(p1);
|
|
foreach(var d2 in dirs)
|
|
{
|
|
Point p2 = new Point(p1.X + d2.X, p1.Y + d2.Y);
|
|
if(tiles.Contains(p2))
|
|
zones.Add(p2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return zones;
|
|
}
|
|
|
|
Point findsafe(Point me, HashSet<Point> bad)
|
|
{
|
|
if(!bad.Any()) return tiles.First();
|
|
|
|
double best = double.MinValue;
|
|
Point spot = me;
|
|
|
|
foreach(var t in tiles)
|
|
{
|
|
if(bad.Contains(t)) continue;
|
|
|
|
double score = 0;
|
|
|
|
double mindist = double.MaxValue;
|
|
foreach(var b in bad)
|
|
{
|
|
double d = Math.Abs(t.X - b.X) + Math.Abs(t.Y - b.Y);
|
|
mindist = Math.Min(mindist, d);
|
|
score += d;
|
|
}
|
|
|
|
score += mindist * 100;
|
|
|
|
if(adj.ContainsKey(t))
|
|
{
|
|
int exits = adj[t].Count(n => !bad.Contains(n));
|
|
score += exits * 10;
|
|
}
|
|
|
|
double dist = Math.Abs(t.X - me.X) + Math.Abs(t.Y - me.Y);
|
|
score -= dist * 0.5;
|
|
|
|
if(score > best)
|
|
{
|
|
best = score;
|
|
spot = t;
|
|
}
|
|
}
|
|
|
|
return spot;
|
|
}
|
|
|
|
Point pathto(Point me, Point goal, HashSet<Point> d1, HashSet<Point> d2, HashSet<Point> d3)
|
|
{
|
|
if(!adj.ContainsKey(me)) return me;
|
|
|
|
if(hist.Count >= 3)
|
|
{
|
|
var last3 = hist.TakeLast(3).ToArray();
|
|
if(last3[0] == last3[2] && last3[0] != last3[1])
|
|
{
|
|
stuck++;
|
|
if(stuck > 2)
|
|
{
|
|
var esc = adj[me]
|
|
.Where(n => !d1.Contains(n))
|
|
.OrderBy(n => Guid.NewGuid())
|
|
.FirstOrDefault();
|
|
if(!esc.Equals(default(Point)))
|
|
{
|
|
stuck = 0;
|
|
return esc;
|
|
}
|
|
}
|
|
}
|
|
else stuck = 0;
|
|
}
|
|
|
|
double best = double.MinValue;
|
|
Point move = me;
|
|
|
|
foreach(var n in adj[me])
|
|
{
|
|
if(d1.Contains(n)) continue;
|
|
|
|
double score = 0;
|
|
|
|
if(d2.Contains(n)) score -= 800;
|
|
if(d3.Contains(n)) score -= 400;
|
|
|
|
double dist = Math.Abs(n.X - goal.X) + Math.Abs(n.Y - goal.Y);
|
|
score -= dist * 100;
|
|
|
|
foreach(var duck in ducks.Values)
|
|
{
|
|
double dd = Math.Abs(n.X - duck.pos.X) + Math.Abs(n.Y - duck.pos.Y);
|
|
score += dd * 10;
|
|
}
|
|
|
|
if(adj.ContainsKey(n))
|
|
{
|
|
int safe = adj[n].Count(x => !d1.Contains(x));
|
|
score += safe * 20;
|
|
|
|
if(safe == 0 && d2.Contains(n))
|
|
score -= 2000;
|
|
}
|
|
|
|
if(!prev.Equals(default(Point)) && n.Equals(prev))
|
|
score -= 50;
|
|
|
|
if(score > best)
|
|
{
|
|
best = score;
|
|
move = n;
|
|
}
|
|
}
|
|
|
|
return move;
|
|
}
|
|
|
|
Point getmove(Point me, Point goal, HashSet<Point> d1, HashSet<Point> d2, HashSet<Point> d3)
|
|
{
|
|
if(!adj.ContainsKey(me)) return me;
|
|
|
|
if(hist.Count >= 3)
|
|
{
|
|
var last3 = hist.TakeLast(3).ToArray();
|
|
if(last3[0] == last3[2] && last3[0] != last3[1])
|
|
{
|
|
stuck++;
|
|
if(stuck > 1)
|
|
{
|
|
var any = adj[me]
|
|
.Where(n => !d1.Contains(n))
|
|
.OrderBy(n => d2.Contains(n) ? 1 : 0)
|
|
.FirstOrDefault();
|
|
if(!any.Equals(default(Point)))
|
|
{
|
|
stuck = 0;
|
|
return any;
|
|
}
|
|
}
|
|
}
|
|
else stuck = 0;
|
|
}
|
|
|
|
double best = double.MinValue;
|
|
Point move = me;
|
|
|
|
foreach(var n in adj[me])
|
|
{
|
|
if(d1.Contains(n)) continue;
|
|
|
|
if(!prev.Equals(default(Point)) && n.Equals(prev))
|
|
continue;
|
|
|
|
double score = 0;
|
|
|
|
if(d2.Contains(n)) score -= 1000;
|
|
if(d3.Contains(n)) score -= 500;
|
|
|
|
double dist = Math.Abs(n.X - goal.X) + Math.Abs(n.Y - goal.Y);
|
|
score -= dist * 10;
|
|
|
|
foreach(var duck in ducks.Values)
|
|
{
|
|
double dd = Math.Abs(n.X - duck.pos.X) + Math.Abs(n.Y - duck.pos.Y);
|
|
score += dd * 20;
|
|
}
|
|
|
|
if(adj.ContainsKey(n))
|
|
{
|
|
int exits = adj[n].Count(x => !d1.Contains(x) && !d2.Contains(x));
|
|
score += exits * 50;
|
|
}
|
|
|
|
if(score > best)
|
|
{
|
|
best = score;
|
|
move = n;
|
|
}
|
|
}
|
|
|
|
return move;
|
|
}
|
|
|
|
OnIntercept(Out["MoveAvatar"], e => {
|
|
var pkt = e.Packet;
|
|
int x = pkt.ReadInt();
|
|
int y = pkt.ReadInt();
|
|
|
|
dest = new Point(x, y);
|
|
forcedest = true;
|
|
desttime = DateTime.UtcNow;
|
|
});
|
|
|
|
OnEnteredRoom(e => {
|
|
ducks.Clear();
|
|
hist.Clear();
|
|
prev = default(Point);
|
|
stuck = 0;
|
|
forcedest = false;
|
|
dest = default(Point);
|
|
floorPlanParsed = false;
|
|
ParseFloorPlan();
|
|
});
|
|
|
|
OnIntercept(In["WiredMovements"], e => {
|
|
var pkt = e.Packet;
|
|
int cnt = pkt.ReadInt();
|
|
|
|
for(int i = 0; i < cnt; i++)
|
|
{
|
|
pkt.ReadInt();
|
|
int fx = pkt.ReadInt();
|
|
int fy = pkt.ReadInt();
|
|
int tx = pkt.ReadInt();
|
|
int ty = pkt.ReadInt();
|
|
pkt.ReadString();
|
|
pkt.ReadString();
|
|
int id = pkt.ReadInt();
|
|
pkt.ReadInt();
|
|
pkt.ReadInt();
|
|
|
|
long fid = id;
|
|
Point newp = new Point(tx, ty);
|
|
Point oldp = new Point(fx, fy);
|
|
|
|
if(!ducks.ContainsKey(fid))
|
|
{
|
|
ducks[fid] = new Duck { id = fid };
|
|
}
|
|
|
|
var d = ducks[fid];
|
|
d.lastpos = d.pos;
|
|
d.pos = newp;
|
|
d.vel = new Point(tx - fx, ty - fy);
|
|
d.lastseen = DateTime.UtcNow;
|
|
|
|
d.trail.Enqueue(newp);
|
|
if(d.trail.Count > 10) d.trail.Dequeue();
|
|
|
|
if((d.lastseen - DateTime.UtcNow).TotalSeconds < 1)
|
|
{
|
|
d.spd = Math.Sqrt(Math.Pow(d.vel.X, 2) + Math.Pow(d.vel.Y, 2));
|
|
}
|
|
}
|
|
});
|
|
|
|
OnIntercept(In["UserUpdate"], e => {
|
|
if(Self == null) return;
|
|
|
|
var pkt = e.Packet;
|
|
int num = pkt.ReadInt();
|
|
|
|
for(int i = 0; i < num; i++)
|
|
{
|
|
int idx = pkt.ReadInt();
|
|
int x = pkt.ReadInt();
|
|
int y = pkt.ReadInt();
|
|
string z = pkt.ReadString();
|
|
pkt.ReadInt();
|
|
pkt.ReadInt();
|
|
string act = pkt.ReadString();
|
|
|
|
if(idx == Self.Index)
|
|
{
|
|
prev = curr;
|
|
curr = new Point(x, y);
|
|
|
|
hist.Enqueue(curr);
|
|
if(hist.Count > 5) hist.Dequeue();
|
|
|
|
if(forcedest && curr.Equals(dest))
|
|
{
|
|
forcedest = false;
|
|
}
|
|
|
|
if(act.Contains("/mv"))
|
|
{
|
|
var parts = act.Split(new[] {' ', '/', ','}, StringSplitOptions.RemoveEmptyEntries);
|
|
if(parts.Length >= 4 && parts[0] == "mv")
|
|
{
|
|
if(int.TryParse(parts[1], out int mx) &&
|
|
int.TryParse(parts[2], out int my) &&
|
|
double.TryParse(parts[3], NumberStyles.Any, CultureInfo.InvariantCulture, out double mz))
|
|
{
|
|
tgt = new Tile(mx, my, mz);
|
|
lastcmd = default(Point);
|
|
}
|
|
}
|
|
}
|
|
else if(act.EndsWith("//") && !act.Contains("/mv"))
|
|
{
|
|
tgt = null;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
while(Run)
|
|
{
|
|
try
|
|
{
|
|
if(!floorPlanParsed) ParseFloorPlan();
|
|
if(!floorPlanParsed) { Delay(50); continue; }
|
|
|
|
Point me = getpos();
|
|
if(me.Equals(default(Point))) { Delay(20); continue; }
|
|
|
|
var toRemove = ducks.Where(d => (DateTime.UtcNow - d.Value.lastseen).TotalSeconds > 5)
|
|
.Select(d => d.Key)
|
|
.ToList();
|
|
foreach(var id in toRemove)
|
|
{
|
|
ducks.Remove(id);
|
|
}
|
|
|
|
if(ducks.Any() || forcedest)
|
|
{
|
|
var d1 = predict(1);
|
|
var d2 = predict(2);
|
|
var d3 = predict(3);
|
|
|
|
Point goal;
|
|
Point next = me;
|
|
|
|
if(forcedest && tiles.Contains(dest))
|
|
{
|
|
if((DateTime.UtcNow - desttime).TotalSeconds > 30)
|
|
{
|
|
forcedest = false;
|
|
goal = findsafe(me, d1);
|
|
next = getmove(me, goal, d1, d2, d3);
|
|
}
|
|
else
|
|
{
|
|
goal = dest;
|
|
next = pathto(me, goal, d1, d2, d3);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
goal = findsafe(me, d1);
|
|
next = getmove(me, goal, d1, d2, d3);
|
|
}
|
|
|
|
if(!next.Equals(me))
|
|
{
|
|
go(next.X, next.Y);
|
|
}
|
|
}
|
|
}
|
|
catch(Exception ex)
|
|
{
|
|
}
|
|
|
|
Delay(20);
|
|
} |