[PATCH] Fixes: item pickup problems; deadlock attack positio

Forum closed. All further discussion to be discussed at https://github.com/OpenKore/

Moderator: Moderators

Message
Author
Beechbone
Noob
Noob
Posts: 7
Joined: 01 Nov 2013, 17:47
Noob?: No

[PATCH] Fixes: item pickup problems; deadlock attack positio

#1 Post by Beechbone »

First, is needed for "pickup problems" and "deadlock positioning":

Code: Select all

--- untouched/openkore_ready/src/Utils.pm	Sun Sep 08 22:00:04 2013
+++ openkore_ready/src/Utils.pm	Fri Nov 01 22:30:21 2013
@@ -38,7 +38,7 @@
 	@{$Utils::DataStructures::EXPORT_TAGS{all}},
 
 	# Math
-	qw(calcPosFromTime calcPosition calcTime checkMovementDirection countSteps distance
+	qw(calcPosFromTime calcPosition calcTime checkMovementDirection countSteps distance distance_steps
 	intToSignedInt intToSignedShort
 	blockDistance getVector moveAlong moveAlongVector
 	normalize vectorToDegree max min round ceil),
@@ -291,6 +291,31 @@
         %line = %{$pos1};
     }
     return sqrt($line{x} ** 2 + $line{y} ** 2);
+}
+
+##
+# distance_steaps(r_hash1, r_hash2)
+# pos1, pos2: references to position hash tables.
+# Returns: the distance as a number.
+#
+# Calculates the maximum horizontal or vertical distance
+# between pos1 and pos2. Use this to find out if a position
+# is within your reach.
+#
+# FIXME: This is not actually the number of steps one
+# has to take to reach the target.
+#
+sub distance_steps {
+    my $pos1 = shift;
+    my $pos2 = shift;
+    return 0 if (!$pos1 || !$pos2);
+    
+    my ($dx, $dy) = (
+    	abs($pos1->{x} - $pos2->{x}),
+    	abs($pos1->{y} - $pos2->{y})
+    );
+    
+    return $dx > $dy ? $dx : $dy;
 }
 
 ##
---

This fixes the annoying problem that openkore fails to pickup items so often:

Code: Select all

--- untouched/openkore_ready/src/AI/CoreLogic.pm	Sat Jun 08 02:00:02 2013
+++ openkore_ready/src/AI/CoreLogic.pm	Fri Nov 01 22:35:33 2013
@@ -736,14 +738,32 @@
 	if (AI::action eq "take" && !(my $item = $items{AI::args->{ID}})) {
 		AI::dequeue;
 
+	} elsif (AI::action eq "take" && ($item->{take_failed} < 2) && timeOut(AI::args->{ai_take_giveup})) {
+		$item->{take_failed}++;
+		my $myPos = $char->{pos};
+		my $dist = distance_steps($item->{pos}, $myPos);
+		if ($dist > 0) {
+			AI::args->{ai_take_giveup}{time} = time(); # reset timer
+			if (!$config{itemsTakeAuto_new}) {
+				$char->move($item->{pos}{x}, $item->{pos}{y});
+			} else {
+				my $pos = $item->{pos};
+				message TF("Routing to (%s, %s) to take %s (%s), distance %s\n", $pos->{x}, $pos->{y}, $item->{name}, $item->{binID}, $dist);
+				ai_route($field->baseName, $pos->{x}, $pos->{y}, maxRouteDistance => $config{'attackMaxRouteDistance'});
+			}
+			message TF("Failed to take %s (%s) from (%s, %s) to (%s, %s) --- moving towards item\n", $item->{name}, $item->{binID}, $char->{pos}{x}, $char->{pos}{y}, $item->{pos}{x}, $item->{pos}{y});
+		} else {
+			message TF("Failed to take %s (%s) from (%s, %s) to (%s, %s) --- standing on top of it\n", $item->{name}, $item->{binID}, $char->{pos}{x}, $char->{pos}{y}, $item->{pos}{x}, $item->{pos}{y});
+			AI::dequeue;
+		}
 	} elsif (AI::action eq "take" && timeOut(AI::args->{ai_take_giveup})) {
 		message TF("Failed to take %s (%s) from (%s, %s) to (%s, %s)\n", $item->{name}, $item->{binID}, $char->{pos}{x}, $char->{pos}{y}, $item->{pos}{x}, $item->{pos}{y});
 		$item->{take_failed}++;
I reuse the ai_take_giveup here, so one might actually want to lower it a bit. Otherwise the bot will wait twice as long for items it cannot pickup for legitimate reasons.

---

This fixes a deadlock(!) situation openkore encounters when it tries to attack mobs that wont move and the attack position it want's to move to is not walkable.

Example: (Mushroom)(empty)(tree)(bot)

Code: Select all

--- untouched/openkore_ready/src/AI/Attack.pm	Sat Apr 06 03:00:02 2013
+++ openkore_ready/src/AI/Attack.pm	Tue Oct 29 23:40:22 2013
@@ -518,6 +521,29 @@
 		$args->{monsterPos} = {%{$monsterPos}};
 
 		my $pos = meetingPosition($target, $args->{attackMethod}{maxDistance});
+
+		if (not $field->isWalkable($pos->{x}, $pos->{y}) and distance_steps($realMyPos, $pos) < 2) {
+			# bad case of hitting a wall
+			# try to find an alternative position with the same distance
+			my ($tx, $ty, $td, $t) = (0,0,999, distance($realMonsterPos->{pos}, $pos));
+			for my $try ([-1, -1], [-1, 0], [-1, 1], [0, -1], [0, 1], [1, -1], [1, 0], [1, 1]) {
+				next unless $field->isWalkable($pos->{x} + $try->[0], $pos->{y} + $try->[1]);
+				next if distance_steps($realMyPos, { x => $pos->{x} + $try->[0], y => $pos->{y} + $try->[1]}) < 1;
+				my $d = abs($t - distance({ x => $pos->{x} + $try->[0], y => $pos->{y} + $try->[1]}, $pos));
+				if ($d < $td) {
+					($tx, $ty, $td) = ($pos->{x} + $try->[0], $pos->{y} + $try->[1], $d);
+				}
+			}
+			if ($td < 999) {
+				($pos->{x}, $pos->{y}) = ($tx, $ty);
+			} else {
+				# now what?
+				# move one random step
+				while (not $field->isWalkable($pos->{x}, $pos->{y})) {
+					($pos->{x}, $pos->{y}) = ($realMyPos->{x} + int(rand(3)-2), $realMyPos->{y} + int(rand(3)-2));
+				}
+			}
+		}
 
 		my $dist = sprintf("%.1f", $monsterDist);
 		debug "Target distance $dist is >$args->{attackMethod}{maxDistance}; moving to target: " .
It is not perfect, some times the bot will do a little "sidestep & back" dance for a while, but it will break the deadlock eventually.

I tried to be very careful, but I only tested it with melee characters. But I think the LOS checking may prevent this from happening for the others.

---

And now a new feature. Or maybe a bug fix? I don't know, but autoStorage already works for items in the cart; this will do the same for autoSell:

Code: Select all

--- untouched/openkore_ready/src/AI/CoreLogic.pm	Sat Jun 08 02:00:02 2013
+++ openkore_ready/src/AI/CoreLogic.pm	Fri Nov 01 22:35:33 2013
@@ -1483,6 +1503,37 @@
 					noSitAuto => 1);
 			}
 		} else {
+
+		if (!defined($args->{'emptiedCart'})) {
+			# get item to sell from cart
+			$args->{'emptiedCart'} = 1;
+			if ($char->cartActive) {
+				my @getItems;
+				my $cartInventory = $cart{inventory};
+				my $max;
+	
+				$max = @{$cartInventory};
+				for (my $i = 0; $i < $max; $i++) {
+					my $cartItem = $cartInventory->[$i];
+					next unless ($cartItem);
+					my $control = items_control($cartItem->{name});
+					next unless ($control->{sell});
+					my $amount = $cartItem->{amount};
+					if ($amount > 0) {
+						my %obj;
+						$obj{index} = $i;
+						$obj{amount} = $amount;
+						push @getItems, \%obj;
+						debug "Scheduling $cartItem->{name} ($i) x $obj{amount} for getting from cart to sell\n", "ai_autoCart";
+					}
+				}
+				if (@getItems) {
+					cartGet(\@getItems);
+					return;
+				}
+			}
+		}
+
 			$args->{'npc'} = {};
 			getNPCInfo($config{'sellAuto_npc'}, $args->{'npc'});
 			if (!defined($args->{'sentSell'})) {
This will (partially) fail if the character becomes overweight with the stuff from the cart. With fail = not sell all items that are in the cart. Especially stacks that have to be split to be moved into the inventory won't work with this. But to do it right I'd have to change the autoSell logic big time.

User avatar
kLabMouse
Administrator
Administrator
Posts: 1301
Joined: 24 Apr 2008, 12:02

Re: [PATCH] Fixes: item pickup problems; deadlock attack positio

#2 Post by kLabMouse »

Nice one!
Developers/Testers please check this patch (may-be make modifications where needed) and to SVN asap. ;)

Locked