Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
356852c
ReworkNewAStarAvoid
Henrybk Mar 20, 2026
4fe8134
add configmodify
Henrybk Mar 20, 2026
cb0c994
rename keys
Henrybk Mar 20, 2026
3f4c642
changed plugin name
Henrybk Mar 20, 2026
86e99cf
fix configmodify
Henrybk Mar 22, 2026
7003ea4
clean keys
Henrybk Mar 22, 2026
5d77a55
config
Henrybk Mar 22, 2026
091d6f2
add avoidObstaclesCellsInMap and avoidObstaclesDefaultPortals
Henrybk Mar 23, 2026
fca4c8e
v3
Henrybk Mar 23, 2026
9e9161e
openListAdd with closed items
Henrybk Mar 23, 2026
5dbb6e1
rename command
Henrybk Mar 23, 2026
7e2b85d
cache map
Henrybk Mar 23, 2026
29ada4b
again
Henrybk Mar 23, 2026
36c30a1
getMeetingPositionCandidateSpots
Henrybk Mar 23, 2026
608a0f2
cache danger
Henrybk Mar 23, 2026
0636183
Change dist to profile in config txt
Henrybk Mar 23, 2026
88dd3bd
step sysm
Henrybk Mar 23, 2026
0e98131
current_move_step_index
Henrybk Mar 23, 2026
beae356
config
Henrybk Mar 23, 2026
c1d5e47
route
Henrybk Mar 24, 2026
c4e7216
comments
Henrybk Mar 24, 2026
765bbd5
cache per obstacle
Henrybk Mar 24, 2026
1598fce
debugs
Henrybk Mar 24, 2026
80da9f4
last todo
Henrybk Mar 25, 2026
7dec805
temp test
Henrybk Mar 25, 2026
f2e46b1
predictor
Henrybk Mar 25, 2026
c62cc18
prohibit danger cells in meeting
Henrybk Mar 26, 2026
959191b
improve position prediction and attack timing logic
Henrybk Mar 27, 2026
17e63d7
adjust obstacle avoidance and AI timing parameters
Henrybk Mar 27, 2026
2350c79
no sol
Henrybk Mar 27, 2026
1c769b3
headers
Henrybk Mar 27, 2026
0bf43e1
timers
Henrybk Mar 27, 2026
65241bc
debugs plugin update
Henrybk Mar 27, 2026
74919c8
remove test
Henrybk Mar 27, 2026
f9801d3
caching
Henrybk Mar 27, 2026
9983b08
add limitations
Henrybk Mar 27, 2026
331ca36
Merge branch 'master' into reworkPathAvoid
Henrybk Mar 28, 2026
9c118d3
fix merge
Henrybk Mar 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion control/config.txt
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,6 @@ lockMap_randY
route_escape_reachedNoPortal 1
route_escape_randomWalk 1
route_escape_shout
route_avoidWalls 1
route_randomWalk 1
route_randomWalk_inLockOnly 0
route_randomWalk_inTown 0
Expand All @@ -237,6 +236,7 @@ route_removeMissingPortals_NPC 1
route_removeMissingPortals 0
route_tryToGuessMissingPortalByDistance 1
route_reAddMissingPortals 1
route_avoidWalls 1
route_randomFactor 0

# Eden Group Headquarters exit portal.
Expand Down Expand Up @@ -1044,3 +1044,29 @@ logToFile_Errors
logToFile_Messages
logToFile_Warnings
history_max 50

avoidObstacles_enable_move 0
avoidObstacles_enable_remove 1
avoidObstacles_enable_avoid_portals 1
avoidObstacles_adjust_route_step 1
avoidObstacles_weight_limit 65000

avoidObstaclesDefaultPortals {
enabled 1
penalty_dist 1000, 1000, 1000, 20
danger_dist 10, 10, 10, 1
prohibited_dist 2
drop_target_when_near_dist 3
drop_destination_when_near_dist 3
}

avoidObstaclesMonster 1368 {
enabled 1
penalty_dist 20000, 20000, 20000, 20000, 30, 7
danger_dist 10, 10, 10, 10, 1
prohibited_dist -1
drop_target_when_near_dist 4
drop_destination_when_near_dist 4
}


12 changes: 7 additions & 5 deletions control/timeouts.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ ai_attack_auto 0.5
ai_homunculus_attack_auto 0.5
ai_mercenary_attack_auto 0.5

ai_attack_route_adjust 0.3
ai_homunculus_route_adjust 0.3
ai_mercenary_route_adjust 0.3
ai_attack_route_adjust 0.15
ai_homunculus_route_adjust 0.15
ai_mercenary_route_adjust 0.15

# Ignore monster for x seconds if there is no route to it
ai_attack_failedLOS 12
Expand Down Expand Up @@ -219,5 +219,7 @@ patchserver 120
# Time to wait before load map in xKore mode
ai_clientSuspend 1

meetingPosition_extra_time_actor 0.2
meetingPosition_extra_time_target 0.5
ai_route_position_prediction_delay 0.05
meetingPosition_future_reachability_lookup 0.3

ai_attack_allowed_waitForTarget 0.3
254 changes: 254 additions & 0 deletions fields/tools/compareFields/compare.pl
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
#!/usr/bin/perl
use strict;
use warnings;

use constant {
TILE_NOWALK => 0,
TILE_WALK => 1,
TILE_SNIPE => 2,
TILE_WATER => 4,
TILE_CLIFF => 8,
};

my $DEFAULT_LIMIT = 200;

main();

sub main {
my %options = parse_args(@ARGV);
my $left = read_fld2($options{left});
my $right = read_fld2($options{right});

print "Comparing '$left->{path}' with '$right->{path}'\n";
print "Left map : $left->{width} x $left->{height}\n";
print "Right map: $right->{width} x $right->{height}\n";

if ($left->{width} != $right->{width} || $left->{height} != $right->{height}) {
print "Map dimensions differ; comparing only the overlapping area.\n";
}

my $comparison = compare_maps($left, $right);
print_comparison($comparison, $options{limit});
}

sub parse_args {
my @args = @_;
my %options = (
limit => $DEFAULT_LIMIT,
);

while (@args) {
my $arg = shift @args;
if ($arg eq '--limit') {
die usage() unless @args;
my $limit = shift @args;
die "Invalid --limit value '$limit'.\n" . usage() unless $limit =~ /^\d+$/;
$options{limit} = $limit;
} elsif (!$options{left}) {
$options{left} = $arg;
} elsif (!$options{right}) {
$options{right} = $arg;
} else {
die "Unexpected argument '$arg'.\n" . usage();
}
}

die usage() unless $options{left} && $options{right};
return %options;
}

sub usage {
return "Usage: perl compare.pl <left.fld2> <right.fld2> [--limit N]\n";
}

sub read_fld2 {
my ($path) = @_;
open my $fh, '<', $path or die "Cannot open $path for reading: $!\n";
binmode $fh;

my $raw = do { local $/; <$fh> };
close $fh;

die "$path is too small to be a valid .fld2 file.\n" unless defined $raw && length($raw) >= 4;

my ($width, $height) = unpack('v2', substr($raw, 0, 4));
my $expected_tiles = $width * $height;
my $tile_data = substr($raw, 4);
my $actual_tiles = length($tile_data);

die "$path has incomplete tile data. Expected $expected_tiles bytes, got $actual_tiles.\n"
if $actual_tiles < $expected_tiles;

if ($actual_tiles > $expected_tiles) {
print "Warning: $path contains " . ($actual_tiles - $expected_tiles) . " trailing bytes after tile data.\n";
$tile_data = substr($tile_data, 0, $expected_tiles);
}

return {
path => $path,
width => $width,
height => $height,
tiles => [unpack('C*', $tile_data)],
};
}

sub compare_maps {
my ($left, $right) = @_;
my $compare_width = min($left->{width}, $right->{width});
my $compare_height = min($left->{height}, $right->{height});

my @changes;
my %transition_counts;
my %row_counts;
my ($min_x, $min_y, $max_x, $max_y);

for my $y (0 .. $compare_height - 1) {
for my $x (0 .. $compare_width - 1) {
my $left_value = tile_at($left, $x, $y);
my $right_value = tile_at($right, $x, $y);
next if $left_value == $right_value;

push @changes, {
x => $x,
y => $y,
left => $left_value,
right => $right_value,
};

$transition_counts{"$left_value->$right_value"}++;
$row_counts{$y}++;

$min_x = $x if !defined $min_x || $x < $min_x;
$max_x = $x if !defined $max_x || $x > $max_x;
$min_y = $y if !defined $min_y || $y < $min_y;
$max_y = $y if !defined $max_y || $y > $max_y;
}
}

my $left_extra = count_extra_cells($left, $compare_width, $compare_height);
my $right_extra = count_extra_cells($right, $compare_width, $compare_height);

return {
left => $left,
right => $right,
compare_width => $compare_width,
compare_height => $compare_height,
changes => \@changes,
transition_counts => \%transition_counts,
row_counts => \%row_counts,
bounds => defined $min_x ? { min_x => $min_x, min_y => $min_y, max_x => $max_x, max_y => $max_y } : undef,
left_extra => $left_extra,
right_extra => $right_extra,
};
}

sub count_extra_cells {
my ($map, $compare_width, $compare_height) = @_;
my $extra = 0;

for my $y (0 .. $map->{height} - 1) {
for my $x (0 .. $map->{width} - 1) {
next if $x < $compare_width && $y < $compare_height;
$extra++;
}
}

return $extra;
}

sub tile_at {
my ($map, $x, $y) = @_;
return $map->{tiles}[($y * $map->{width}) + $x];
}

sub print_comparison {
my ($comparison, $limit) = @_;
my $changes = $comparison->{changes};
my $change_count = scalar @{$changes};

if (!$change_count && !$comparison->{left_extra} && !$comparison->{right_extra}) {
print "The two maps are identical.\n";
return;
}

print "Compared area: $comparison->{compare_width} x $comparison->{compare_height}\n";
print "Changed cells in overlap: $change_count\n";

if ($comparison->{bounds}) {
my $bounds = $comparison->{bounds};
print "Change bounds: x $bounds->{min_x}..$bounds->{max_x}, y $bounds->{min_y}..$bounds->{max_y}\n";
}

print "Cells only present on left map: $comparison->{left_extra}\n" if $comparison->{left_extra};
print "Cells only present on right map: $comparison->{right_extra}\n" if $comparison->{right_extra};

if (%{ $comparison->{transition_counts} }) {
print "\nTransition summary:\n";
foreach my $transition (sort {
$comparison->{transition_counts}{$b} <=> $comparison->{transition_counts}{$a} || $a cmp $b
} keys %{ $comparison->{transition_counts} }) {
my ($left_value, $right_value) = split /->/, $transition, 2;
printf " %3d %-23s -> %3d %-23s : %d cells\n",
$left_value,
describe_tile($left_value),
$right_value,
describe_tile($right_value),
$comparison->{transition_counts}{$transition};
}
}

if (%{ $comparison->{row_counts} }) {
print "\nRows with changes:\n";
foreach my $y (sort { $a <=> $b } keys %{ $comparison->{row_counts} }) {
print " y=$y : $comparison->{row_counts}{$y} changed cells\n";
}
}

print "\nChanged cells";
print " (showing up to $limit)" if $limit;
print ":\n";

my $shown = 0;
foreach my $change (@{$changes}) {
last if $limit && $shown >= $limit;
printf " (%d, %d): %3d %-23s -> %3d %-23s\n",
$change->{x},
$change->{y},
$change->{left},
describe_tile($change->{left}),
$change->{right},
describe_tile($change->{right});
$shown++;
}

if ($limit && $change_count > $limit) {
print " ... " . ($change_count - $limit) . " more changed cells omitted\n";
}
}

sub describe_tile {
my ($value) = @_;
my %known = (
TILE_NOWALK() => 'nowalk',
TILE_WALK() => 'walk',
TILE_WATER() => 'water',
TILE_WALK() | TILE_WATER() => 'walk|water',
TILE_WATER() | TILE_SNIPE() => 'water|snipe',
TILE_CLIFF() => 'cliff',
TILE_CLIFF() | TILE_SNIPE() => 'cliff|snipe',
);

return $known{$value} if exists $known{$value};

my @parts;
push @parts, 'walk' if ($value & TILE_WALK) == TILE_WALK;
push @parts, 'snipe' if ($value & TILE_SNIPE) == TILE_SNIPE;
push @parts, 'water' if ($value & TILE_WATER) == TILE_WATER;
push @parts, 'cliff' if ($value & TILE_CLIFF) == TILE_CLIFF;

return @parts ? join('|', @parts) : 'none';
}

sub min {
return $_[0] < $_[1] ? $_[0] : $_[1];
}
Loading
Loading