feat: Add auto dodge

This commit is contained in:
VAC committed 2026-10-16 00:39:02 -03:00
1 parent afb8235c08
commit 6701dd0305
8 files changed
+150 -2

No files matched your search

+1
View File
@@ -57,6 +57,7 @@ public static class Hotkeys
Toggle("Combat", "WeakenEnemies", "Weaken Enemies", () => Settings.WeakenEnemies, v => Settings.WeakenEnemies = v),
Toggle("Combat", "RapidAttack", "Rapid Attack", () => Settings.RapidAttack, v => Settings.RapidAttack = v),
Toggle("Combat", "MagicBullets", "Magic Bullets", () => Settings.MagicBullets, v => Settings.MagicBullets = v),
Toggle("Combat", "AutoDodge", "Auto Dodge", () => Settings.AutoDodge, v => Settings.AutoDodge = v),
new("Combat", "GatherAll", "Gather All Enemies", CombatFeatures.GatherAll),
new("Combat", "KillAll", "Kill All Enemies", CombatFeatures.KillAll),
+1
View File
@@ -59,6 +59,7 @@ public static partial class Settings
[nameof(AimFov)] = "Combat.Aim.CursorRadius",
[nameof(AimRange)] = "Combat.Aim.Range",
[nameof(MagicBullets)] = "Combat.MagicBullets",
[nameof(AutoDodge)] = "Combat.AutoDodge",
[nameof(InstantBreak)] = "Items.InstantBreak",
[nameof(InfItems)] = "Items.InfiniteItems",
+1 -1
View File
@@ -35,7 +35,7 @@ public static partial class Settings
public static bool KillAura, HitMagnet, FreezeEnemies, WeakenEnemies;
public static float KillAuraRange = 20f, HitMagnetRange = 30f;
public static int KillAuraInterval = 10;
public static bool Aimbot, AimPrediction = true, AimDrawTarget = true, AutoAttack, AimExact = true, ShotPreview, MagicBullets;
public static bool Aimbot, AimPrediction = true, AimDrawTarget = true, AutoAttack, AimExact = true, ShotPreview, MagicBullets, AutoDodge;
public static float AimFov = 250f, AimRange = 60f;
public static bool InstantBreak, InfItems, ItemVacuum, AutoSell, BankButtons = true;
+142
View File
@@ -0,0 +1,142 @@
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Terraria;
using TerraSharp.Core;
using TerraSharp.Simulation;
namespace TerraSharp.Features.Combat;
// Steers the local player out of predicted projectile and contact hits.
public static class AutoDodge
{
const int Horizon = 24;
const int MaxThreats = 48;
const float ScanRange = 60f * 16f;
const float Margin = 6f;
const int WallCheckTicks = 6;
sealed class Threat
{
public readonly Vector2[] Path = new Vector2[Horizon + 1];
public int Count, Width, Height;
}
readonly record struct Move(int Horizontal, int Vertical);
static readonly Move[] Moves = [new(0, 0), new(-1, 0), new(1, 0), new(0, -1), new(-1, -1), new(1, -1), new(0, 1), new(-1, 1), new(1, 1)];
static readonly Threat[] Pool = new Threat[MaxThreats];
static readonly List<Threat> Threats = [];
static AutoDodge()
{
for (int i = 0; i < Pool.Length; i++)
Pool[i] = new Threat();
}
// Player.HorizontalMovement prefix: controls and velocity set here drive this tick's movement.
public static void Steer(Player player)
{
if (!Settings.AutoDodge || player.dead)
return;
CollectThreats(player);
if (Threats.Count == 0)
return;
float speed = Settings.Fly ? Settings.FlySpeed : Math.Max(Math.Max(player.maxRunSpeed, player.accRunSpeed), 3f);
float jump = Player.jumpSpeed * 1.5f;
int baseline = FirstHit(player, player.velocity, false);
if (baseline > Horizon)
return;
Move best = Moves[0];
int bestHit = baseline;
foreach (Move move in Moves)
{
if (move == Moves[0])
continue;
var velocity = new Vector2(move.Horizontal * speed, move.Vertical == 0 ? player.velocity.Y : move.Vertical * jump * player.gravDir);
int hit = FirstHit(player, velocity, true);
if (hit > bestHit)
(best, bestHit) = (move, hit);
}
if (best == Moves[0])
return;
Apply(player, best, speed, jump);
}
static void Apply(Player player, Move move, float speed, float jump)
{
player.controlLeft = move.Horizontal < 0;
player.controlRight = move.Horizontal > 0;
if (move.Horizontal != 0)
player.velocity.X = move.Horizontal * speed;
player.controlUp = move.Vertical < 0;
player.controlDown = move.Vertical > 0;
if (move.Vertical != 0)
player.velocity.Y = move.Vertical * jump * player.gravDir;
}
// First tick a threat overlaps the player moving at this velocity, or Horizon + 1 when none do.
static int FirstHit(Player player, Vector2 velocity, bool checkWalls)
{
Vector2 size = new(player.width, player.height);
if (checkWalls && TileCollision.Sweep(player.Center, player.Center + velocity * WallCheckTicks, player.width, player.height))
return -1;
for (int t = 1; t <= Horizon; t++)
{
Vector2 position = player.position + velocity * t;
var bounds = new Rectangle((int)(position.X - Margin), (int)(position.Y - Margin), (int)(size.X + Margin * 2), (int)(size.Y + Margin * 2));
foreach (Threat threat in Threats)
{
if (t >= threat.Count)
continue;
Vector2 center = threat.Path[t];
if (bounds.Intersects(new Rectangle((int)(center.X - threat.Width / 2f), (int)(center.Y - threat.Height / 2f), threat.Width, threat.Height)))
return t;
}
}
return Horizon + 1;
}
static void CollectThreats(Player player)
{
Threats.Clear();
float rangeSq = ScanRange * ScanRange;
for (int i = 0; i < Main.maxProjectiles && Threats.Count < MaxThreats; i++)
{
Projectile projectile = Main.projectile[i];
if (!projectile.active || !projectile.hostile || projectile.damage <= 0 || Vector2.DistanceSquared(projectile.Center, player.Center) > rangeSq)
continue;
if (!Ballistics.Current(i, out Vector2 velocity, out int age))
(velocity, age) = (projectile.velocity * (1 + projectile.extraUpdates), 0);
Threat threat = Pool[Threats.Count];
threat.Count = Ballistics.Path(Ballistics.Get(projectile.type), projectile.Center, velocity, age, Horizon, threat.Path);
(threat.Width, threat.Height) = (Math.Max(4, projectile.width), Math.Max(4, projectile.height));
Threats.Add(threat);
}
for (int i = 0; i < Main.maxNPCs && Threats.Count < MaxThreats; i++)
{
NPC npc = Main.npc[i];
if (!Hostility.IsHostile(npc) || npc.damage <= 0 || Vector2.DistanceSquared(npc.Center, player.Center) > rangeSq)
continue;
Threat threat = Pool[Threats.Count];
for (int t = 0; t <= Horizon; t++)
threat.Path[t] = npc.Center + NpcMotion.Offset(npc, t);
(threat.Count, threat.Width, threat.Height) = (Horizon + 1, npc.width, npc.height);
Threats.Add(threat);
}
}
}
@@ -2,6 +2,7 @@ using System;
using Microsoft.Xna.Framework;
using Terraria;
using TerraSharp.Core;
using TerraSharp.Features.Combat;
using TerraSharp.UI;
namespace TerraSharp.Features;
@@ -102,6 +103,7 @@ public static class PlayerFeatures
ApplyGhost(player);
ApplyVision(player);
AutoDodge.Steer(player);
}
// ResetEffects clears both every tick; NPC.TargetClosest and SetTargetTrackingValues read them.
+1
View File
@@ -101,6 +101,7 @@ public sealed partial class MainWindow
Slider("Max range", ref Settings.AimRange, 5f, 150f, 60f, "{0:0} tiles");
Toggle("Show target", ref Settings.AimDrawTarget);
});
Toggle("Auto Dodge", ref Settings.AutoDodge);
Toggle("Magic Bullets", ref Settings.MagicBullets);
Toggle("Shot Preview", ref Settings.ShotPreview);
+1
View File
@@ -29,6 +29,7 @@ public sealed partial class MainWindow
["Exact check"] = "Checks and corrects aim before firing. Auto Attack skips known misses. Orange brackets mean an unconfirmed shot.",
["Shot Preview"] = "Shows your next shot's path, including spread and homing.",
["Magic Bullets"] = "Your projectiles home in on the aimbot target or the nearest enemy, through blocks.",
["Auto Dodge"] = "Moves you out of the way of incoming projectiles and enemies.",
["Auto Attack"] = "Swings at enemies in reach and shoots at enemies your weapon can hit.",
["Show target"] = "Shows the cursor radius, target brackets and aim point.",
["Kill Aura"] = "Kills enemies in range and drops their loot.",
+1 -1
View File
@@ -32,7 +32,7 @@ public sealed partial class MainWindow : Window
[
new Page("Player", PlayerPage, () => Count(Settings.GodMode, Settings.InfHealth, Settings.InfMana, Settings.InfBreath, Settings.InfFlight, Settings.InstantRespawn, Settings.AutoHeal, Settings.AutoMana, Settings.GhostMode, Settings.DefenseBoost)),
new Page("Movement", MovementPage, () => Count(Settings.Fly, Settings.SuperSpeed, Settings.HighJump, Settings.GravityFlip, Settings.NoFallDamage, Settings.LavaImmune, Settings.WaterWalk, Settings.NoKnockback, Settings.ExtendedReach)),
new Page("Combat", CombatPage, () => Count(Settings.RapidAttack, Settings.AutoSwing, Settings.DamageBoost, Settings.NoManaCost, Settings.NoSpread, Settings.Aimbot, Settings.AutoAttack, Settings.KillAura, Settings.HitMagnet, Settings.FreezeEnemies, Settings.WeakenEnemies, Settings.MagicBullets)),
new Page("Combat", CombatPage, () => Count(Settings.RapidAttack, Settings.AutoSwing, Settings.DamageBoost, Settings.NoManaCost, Settings.NoSpread, Settings.Aimbot, Settings.AutoAttack, Settings.KillAura, Settings.HitMagnet, Settings.FreezeEnemies, Settings.WeakenEnemies, Settings.MagicBullets, Settings.AutoDodge)),
new Page("Items", ItemsPage, () => Count(Settings.InstantBreak, Settings.InfItems, Settings.ItemVacuum, Settings.AutoSell, Settings.AutoFish, Settings.Sonar)),
new Page("Visuals", VisualsPage, () => Count(Settings.Esp, Settings.Spelunker, Settings.Hunter, Settings.Shine, Settings.NightOwl, Settings.DangerSense, Settings.BiomeSight, Settings.FullBright, Settings.ExtendedZoom)),
new Page("World", WorldPage, () => Count(Settings.FreezeTime, Settings.SpawnRateBoost, Settings.MapTeleport)),