Autowarper, For all your warping needs

Other plugins for extending OpenKore's functionality. This forum is only for posting new plugins and commenting on existing plugins. For support, use the Support forum.

Moderator: Moderators

Message
Author
Bahamut
Noob
Noob
Posts: 17
Joined: 30 Sep 2009, 04:40
Noob?: Yes

Re: Autowarper, For all your warping needs

#11 Post by Bahamut »

i fixed that error but still getting this error when calling autowarp

Code: Select all

Undefined subroutine &autowarper::stopAttack called at autowarper.pl line 232.

EDIT: Ok i just commented that line and i got this working, i hope i didint break anything.
Now the problem is that, the macro just don't overrides the route AI, so the macro is not working. any clue?

romrayla
Noob
Noob
Posts: 1
Joined: 19 Aug 2011, 18:20
Noob?: Yes

Re: Autowarper, For all your warping needs

#12 Post by romrayla »

This is a really nice idea of a plugin. Do we have an updated one for the latest Openkore? :)

I am getting the same %field thing error... which is probably because it has already been retired and $field is now being used instead...

Problem is, I don't know how to get around it. :)

Hope someone updates this.

ptcarino
Plain Yogurt
Plain Yogurt
Posts: 62
Joined: 17 Jul 2010, 00:48
Noob?: No
Location: pRO Valkyrie

Re: Autowarper, For all your warping needs

#13 Post by ptcarino »

Bahamut failed to share his updated code. luckily i managed to make it work too

Code: Select all

# autowarper by Hexo55
# Edited from autowarpn by Joseph and Kissa2k 

package autowarper;

use strict;
use Globals;
use Log qw(message error);
use Utils;
use Network::Send;
use Misc;
use AI;
use Translation;

Plugins::register('autowarper', 'Autowarp for all your warping needs', \&unload);

my $hooks = Plugins::addHooks(
	 ['AI_pre', \&AI_hook],
	 ['packet_skilluse', \&warpopen_hook],
	 ['packet/warp_portal_list', \&warplist_hook],
	 ['Network::Receive::map_changed', \&mapchange_hook],
	 ['player_disappeared', \&playerdisappeared_hook],
	 ['packet_pre/area_spell_disappears', \&portaldisappeared_hook],
	 ['is_casting', \&casting_hook]
);

my $commandsID = Commands::register(
	 ["autowarp", "Autowarp for all your warping needs", \&cmdAutoWarp]
);


#global variables
my $map;
my $move_flag;
my @payload;
my $castTries;
my $isCasting;
my $timeoutBeforeCasting;
my $warpOpened;
my $warpNowOpen;
my $warpCoordinates;

sub unload {
	 Plugins::delHooks($hooks);
	 Commands::unregister($commandsID);
}

sub cmdAutoWarp {
	if (!$net || $net->getState() != Network::IN_GAME) {
		error TF("You must be logged in the game to use this command (%s).\n", shift);
		return;
	}
	elsif (AI::action eq "autowarp") {
		error T("We have already initiated autowarp, wait until it finishes.\n");
		return;
	}

	my (undef, $args_string) = @_;
	my @args = parseArgs($args_string);
	
	#initialize variables
	$castTries = 0;
	$warpOpened = 0;
	$warpNowOpen = 0;
	$move_flag = 0;
	
	if ($args[0] eq 'move') {
		$move_flag = 1;
		shift(@args);
	}

	$map = shift(@args);
	
	# Remove payload from args if it
	# the payload is currently in sight
	@payload = ();
	if (@args){
		foreach my $player (@{$playersList->getItems()}){
			last if (!@args);
			for (my $i = 0; $i < @args; $i++) {
				if ($args[$i] eq $player->{name}) {
					push(@payload, $args[$i]);
					splice(@args, $i, 1);
					last;
				}
			}	
		} 
	}
	
	if (@args) {
		error TF("Payload(s) %s is not in sight.\n", join(', ', @args));
	}
	
	if ($map =~ /^([a-zA-Z]+).*(\d*)$/) {
		# checks if you have the warp skill
		if (!($char->{skills}{AL_WARP}) || !($char->{skills}{AL_WARP}{lv} > 0)) {
			error T("Skill Warp Portal cannot be used because your character has no such skill.\n");
			return;
		}
		# checks if the destination you specify exists
		elsif (!defined $maps_lut{$map.'.rsw'}) {
			error TF("Map '%s' does not exist.\n", $map);
			return;
		}
				
		# add to AI::queue so that the bot will finish first
		# what it is doing before proceeding with autowarp
		# we also need to save AI::args->timeout into a temporary
		# variable since it is cleared whenever we call AI:queue
		# $temp variable is used when we are casting a skill so that
		# we will cast the warp portal after the skill has been cast.
		my $temp = AI::args->{timeout};
		AI::queue("autowarp");	
		AI::args->{timeout} = ($isCasting ? $temp+1 : 1);
		AI::args->{time} = time;
		$timeoutBeforeCasting = 0;
		# We need to stand to be able to cast the skill
		Commands::cmdStand();
		if(@payload) {
			message (sprintf("Now warping payload(s) %s.\n", join(', ', @payload)), "list");
		}	
		message(sprintf("Preparing to cast a warp portal to '%s'.\n", $map), "list");
	}
	else {
		error T("Syntax Error in function 'autowarp'\n" . 
						"Usage: autowarp [move] <field_name> [<player1> <player2> ...]\n");
	}
}

sub mapchange_hook {
	my $ai_string;
	if (@ai_seq) {
		$ai_string =  join(' ', @ai_seq);
	}
	
	# AI::Dequeue is not enough
	# since after moving into warp, the first
	# element in ai_seq is 'route' not 'autowarp'
	# because we invoke main::ai_route 
	if ($ai_string =~ /autowarp/) {
			AI::clear;
			return;
	}		
}

sub playerdisappeared_hook {
	my ($hookmname, $args) = @_;
	
	# This will run only if we are
	# autowarping, we have payloads, and
	# the warp is still open.
	if(AI::action eq "autowarp" && @payload && $warpNowOpen) {
		my $player = $args->{player};
    
    # Remove player from the payload list if
    # he disappeared.	
		for (my $i = 0; $i < @payload; $i++) {
			if ($payload[$i] eq $player->{name}) {
				message (sprintf("Payload %s disappeared.\n", $payload[$i]), "list");
				splice(@payload, $i, 1);
				last;
			}
		}
		
		if (!@payload && !$move_flag) {
			message ("No more Payload.\n", "list");
			AI::dequeue;
			return;
		}
		elsif (!@payload && $move_flag && $warpNowOpen) {
				message (sprintf("Moving into warp portal at (%d, %d).\n",$warpCoordinates->{x},$warpCoordinates->{y}), "list" );
				main::ai_route($field->name(), 	$warpCoordinates->{x}, $warpCoordinates->{y},
						noSitAuto => 1,
						attackOnRoute => 0);
				$move_flag = 0;
		}
	}
}

sub portaldisappeared_hook {
	my ($hookname, $args) = @_;
	
	# This will only run if we are autowarping
	# and we have casted a warp portal
	if(AI::action eq "autowarp" && $warpNowOpen){
		$warpNowOpen = 0;
		my $ID = $args->{ID};
		my $spell = $spells{$ID};
		if (($spell->{type} == 0x81) && ($spell->{sourceID} eq $accountID)) {
			# We need to cast another warp portal immediately 
			AI::args->{timeout} = 1;
			AI::args->{time} = time;
		}
	}
}	

sub AI_hook {
	my $hookName = shift;

	if (timeOut(AI::args)) {
		# If we are casting wait until
		# finishes
		if ($isCasting) {
			# Restore timeout
			AI::args->{timeout} = $timeoutBeforeCasting;
			AI::args->{time} = time;
			$isCasting = 0;
		}
		elsif (AI::action eq "autowarp") {
		
			# Check if we have reached $maxCastTries
			my $maxCastTries = defined($config{'autoWarp_maxCastTries'}) ? $config{'autoWarp_maxCastTries'} : 3;
			if ($castTries >= $maxCastTries) {
				error TF("Unable to cast skill Warp Portal in %d tries.\n", $castTries);
				AI::dequeue;
				return;
			}
			elsif ($warpOpened >= $maxCastTries) {
				error TF("I have already opened %d warp portals for the payloads, I will not open another.\n", $warpOpened);
				AI::dequeue;
				return;
			}	
		
			my $pos = getEmptyBlock($char, 8);
			if ($pos) {
				my $warplvl = $char->{skills}{AL_WARP}{lv};
				
				# This adds a skill task so as not to
				# interfere with current auto skills
				Commands::cmdUseSkill('sl', "27 $pos->{x} $pos->{y}");
				
				#stopAttack();
				message (sprintf("Attempting to open warp portal at (%d, %d).\n",$pos->{x}, $pos->{y}), "list");
				# If we have failed to cast a warp, wait 
				# timeout before casting again
				AI::args->{timeout} = defined($config{'autoWarp_timeout'}) ? $config{'autoWarp_timeout'} : 15;
				AI::args->{time} = time;
				$castTries++;
			}
			else {
				error T("Cannot cast warp portal on current location, move to another location and try again.\n");
				AI::dequeue;
				return;
			}
		}		 
	}
}

sub warplist_hook { 
	if (AI::action eq "autowarp") {
	# checks if you have memo to your target destination
		for (my $i = 0; $i < @{$char->{warp}{memo}}; $i++) {
			last if ($char->{warp}{memo}[$i] eq $map);
			if (($i == @{$char->{warp}{memo}} - 1) && ($char->{warp}{memo}[$i] ne $map)) {
				error TF("You do not have a warp to '%s'.\n", $map);
				# You still need to do this to close the warp list
				$messageSender->sendWarpTele(27, $map. ".gat");
				AI::dequeue;
				return;
			} 
		}
		$messageSender->sendWarpTele(27, $map.".gat");
	}
}

sub warpopen_hook {
	my ($hookname, $args) = @_;
	
	if (AI::action eq "autowarp") {
	 # it's our warp portal!
		if ($args->{sourceID} eq $accountID && $args->{skillID} == 27) {
			$warpCoordinates->{x} = $args->{x};
			$warpCoordinates->{y} = $args->{y};
			$warpOpened++;
			$warpNowOpen = 1;
			$castTries = 0;
			if (@payload) {
					message("Waiting for the payload(s) to enter the warp portal.\n", "list");
					#extend timeout
					AI::args->{timeout} = 30;
					AI::args->{time} = time;
			}
			elsif (!$move_flag) {
				AI::dequeue;
				return;
			}
			elsif (!@payload && $move_flag && $warpNowOpen) {
				message (sprintf("Moving into warp portal at (%d, %d).\n",$warpCoordinates->{x},$warpCoordinates->{y}), "list" );
				main::ai_route($field->name(), 	$warpCoordinates->{x}, $warpCoordinates->{y},
						noSitAuto => 1,
						attackOnRoute => 0);
				$move_flag = 0;
			}
	 	}
	}
}

# This sub adds timeout in case we are
# casting a spell.
sub casting_hook {
	my ($hookname, $args) = @_;
	
	if ($args->{sourceID} eq $accountID) {
		# First we need to store the timeout before casting
		# so we can continue counting after we cast
		$timeoutBeforeCasting = AI::args->{timeout};
		AI::args->{timeout} = int($args->{castTime} / 1000) + 1;
		AI::args->{time} = time;
		$isCasting = 1;
	}
}

# My version of spiral scanning cells around the caster.
# This scans for an empty 3x3 cell around the caster
# up to $maxDist-1. This is slower than the previous
# algorithm since it has to scan more cells.
sub getEmptyBlock {
	my ($obj) = shift;
	my ($maxDist) = shift;
	my $cellPriority = $castTries;

	my $pos;
	
	#Get the position of all players
	foreach (@{$playersList->getItems()}) {
		$pos->{$_->{pos_to}{x}}->{$_->{pos_to}{y}} = 1;
	}

	my $vectorx = {
		1 => -1,
		-1 => 1
	};
		
	my $vectory = {
		-1 => -1,	
		1 => 1
	};
	
	my $target_pos;
	my $cell;
	for (my $i = 2; $i < $maxDist; $i++) {
		$cell->{x} = $i;
		$cell->{y} = $i;
			
		my $traversal_flag = 1;
		for (my $k = 0; $k < ($i*8); $k++) {
			$target_pos->{x} = $obj->{pos_to}{x} + $cell->{x};
			$target_pos->{y} = $obj->{pos_to}{y} + $cell->{y};
			
			
			if(is_subBlockEmpty($target_pos,$pos) && checkLineWalkable($obj->{pos_to}, $target_pos)) {
				# This ensures that if the warp skill failed, the next cast will
				# probably on a new spot.
				if ($cellPriority == 0 && int(rand(2)) == 1) {
					return $target_pos;
				}
				elsif($cellPriority > 0) {
					$cellPriority--;
				}
			}
			$cell->{$traversal_flag ? 'y':'x'} += $traversal_flag ? $vectorx->{$cell->{x}/$i}:$vectory->{$cell->{y}/$i};
			if ($traversal_flag && $vectory->{$cell->{y}/$i}) {
				$traversal_flag = 0;
			}
			elsif (!$traversal_flag && $vectorx->{$cell->{x}/$i}) {
				$traversal_flag = 1;
			}		
		}
	}
	return 0;
}

#Scans if the (3x3) subBlock is empty
sub is_subBlockEmpty {	
		my $center_pos = shift;
		my $pos = shift;
		my $vectors = [
			[0,0],
			[1,1],
			[1,0],
			[1,-1],
			[0,-1],
			[-1,-1],
			[-1,0],
			[-1,1],
			[0,1]
		];
		
		my $posx = 0; 
		my $posy = 0;

		foreach my $coord (@{$vectors}) {
			$posx = ${$coord}[0] + $center_pos->{x};
			$posy = ${$coord}[1] + $center_pos->{y};
			unless ($field->isWalkable($posx, $posy) && !$pos->{$posx}->{$posy}) {
				return 0;
			}
		}	
		return 1;
}
1;
Image

iniesta6
Noob
Noob
Posts: 3
Joined: 03 Jul 2012, 12:44
Noob?: Yes

Re: Autowarper, For all your warping needs

#14 Post by iniesta6 »

When you type autowarp move mapname, why the bot cast portal two times?

Is it only me or this is how it is?

Because the second portal causes problems.

ptcarino
Plain Yogurt
Plain Yogurt
Posts: 62
Joined: 17 Jul 2010, 00:48
Noob?: No
Location: pRO Valkyrie

Re: Autowarper, For all your warping needs

#15 Post by ptcarino »

iniesta6 wrote:When you type autowarp move mapname, why the bot cast portal two times?

Is it only me or this is how it is?

Because the second portal causes problems.
doesn't happen to me.
Image

Post Reply