Code:
########################################
# Wait4Party v1.5 rev a -- Stick Together Team!
# ©2008 by Contrad
#
# This software is open source, licensed under the GNU General Public
# License, version 3.
# Basically, this means that you're allowed to modify and/or distribute
# this software. However, if you distribute modified versions, you MUST
# also distribute the source code.
# See <http://www.gnu.org/licenses/> for the full license.
#
# How to use :
# <config.txt>
# wait4party (<boolean flag>/;)/
# Wait4Party On or Off
#
# wait4party_sameMapOnly (<boolean flag>/;)/
# Only activate if the party member are in the same map
#
# wait4party_waitBySitting (<boolean flag>/;)/
# Don't search, just sit and wait
#
# wait4party_attackOnSearch (0|1S E N S O R)
# 0 = No; 1 = Retaliate; 2 = Yes
# Attacking monster when searching member
#
# wait4party_followSit (<boolean flag>/;)/
# Sitting when party is sitting. ATTENTION! Turn OFF 'followSitAuto' on slave or they'll sit forever!
#
# Jan 5, 2010 ~ Blackmail
# use AI_pre hooks ^^
# Add Features:
# wait4party_ignore [<player names>]
# ignore (comma-separated list of) player names if you lost them.
#
# wait4party_timeout [<seconds>]
# If timeout is exceeded and party doesn't appear on screen, master will search for the missing party.
#
# wait4party_cast [<skills>]
# Wait if party cast (comma-separated list of) skills.
#
# Sep 11, 2010 : add sub emulateCmdSit, fix wait4party_followSit
# Oct 22, 2010 : change %field into $field
##
package wait4party;
use strict;
# use warnings;
# use Data:/:D/umper;
use Plugins;
use Globals qw(%config @partyUsersID $playersList $accountID $char $field %ai_v @ai_seq @ai_seq_args %timeout $taskManager);
use Utils qw(distance timeOut);
use Utils:/:D/ataStructures qw(existsInList);
use Log qw(message warning error debug);
use Translation qw/T TF/;
use constant {\tNAME => 'wait4party' };
my %findParty;
my %partySit;
my @notAI = qw(storageAuto storageGet sellAuto buyAuto attack skill_use);
Plugins::register( NAME, 'Wait for party', \&unload, \&unload);
my $hooks = Plugins::addHooks(
\t['AI_pre', \&waitForOthers, undef],
\t['is_casting', \&waitCast, undef]);
sub unload {
\tPlugins::delHooks($hooks);
\tundef %findParty;
\tundef %partySit;
\tundef @notAI;
}
sub waitForOthers {
\treturn unless ($config{'wait4party'} && @partyUsersID);
\t
\tmy $actor;
\tforeach (@partyUsersID) {
\t\tnext if (!$_ || $_ eq $accountID
\t\t || ($config{'wait4party_ignore'} && existsInList("$config{'wait4party_ignore'}", "$char->{'party'}{'users'}{$_}{'name'}"))
\t\t || ($findParty{ID} && $findParty{ID} ne $_)); # first lost first served
\t\t$actor = $playersList->getByID($_);
\t\t# PARTY MISSING!!
\t\tif(!$actor && $char->{'party'}{'users'}{$_}{'online'}) {
\t\t\t# party Check
\t\t\tmy %party;
\t\t\t$party{x} = $char->{party}{users}{$_}{pos}{x};
\t\t\t$party{y} = $char->{party}{users}{$_}{pos}{y};
\t\t\t($party{map}) = $char->{party}{users}{$_}{map} =~ /([\s\S]*)\.gat/;
\t\t
\t\t\tif ($party{map} ne $field->baseName() || !$party{'x'} || !$party{'y'}
\t\t\t || ($party{'x'} == 0) || ($party{'y'} == 0)) {
\t\t\t\tnext if $config{'wait4party_sameMapOnly'};
\t\t\t\treturn unless timeOut($timeout{ai}{time},5);
\t\t\t\tdelete $party{x};
\t\t\t\tdelete $party{y};
\t\t\t}
\t\t\tnext unless ($party{map} ne $field->baseName || exists $party{x});
\t\t
\t\t\t# set %findParty when party dissappear from screen
\t\t\tif (!$findParty{ID}) {
\t\t\t\t$findParty{ID} = $_;
\t\t\t\t$findParty{time} = time if !$findParty{time};
\t\t\t\t$findParty{timeout} = $config{'wait4party_timeout'} if ($config{'wait4party_timeout'});
\t\t\t\tif ($config{'wait4party_waitBySitting'}) {
\t\t\t\t\tmessage ("Party (".$char->{party}{users}{$_}{name}.") lost, wait by sitting.
", "wait4party");
\t\t\t\t} else {
\t\t\t\t\tmessage ("Party (".$char->{party}{users}{$_}{name}.") lost.
", "wait4party");
\t\t\t\t}
\t\t\t}
\t\t\t# notAI
\t\t\treturn if AI::inQueue(@notAI);
\t\t\tif ($config{'wait4party_waitBySitting'}) {
\t\t\t\temulateCmdSit() if (!$char->{sitting});
\t\t\t\treturn if (!$findParty{timeout}); # wait by sit forever..
\t\t\t}
\t\t\treturn if ($findParty{timeout} && !timeOut(\%findParty));
\t\t\t# Search for Party
\t\t\tif ((exists $ai_v{party} && distance(\%party, $ai_v{party}) > $config{followDistanceMax})
\t\t\t || ($party{map} ne $ai_v{party}{map})
\t\t\t || ($ai_v{party}{time} && timeOut($ai_v{party}{time}, 15) && distance(\%party, $char->{pos_to}) > $config{followDistanceMax})) {
\t\t\t\t$ai_v{party}{x} = $party{x};
\t\t\t\t$ai_v{party}{y} = $party{y};
\t\t\t\t$ai_v{party}{map} = $party{map};
\t\t\t\t$ai_v{party}{time} = time;
\t\t\t\tif ($ai_v{party}{map} ne $field->baseName) {
\t\t\t\t\tmessage TF("Calculating route to find %s: %s
", $char->{party}{users}{$_}{name}, $ai_v{party}{map}), NAME;
\t\t\t\t} elsif (distance(\%party, $char->{pos_to}) > $config{followDistanceMax} ) {
\t\t\t\t\tmessage TF("Calculating route to find %s: %s (%d %d)
", $char->{party}{users}{$_}{name}, $ai_v{party}{map}, $ai_v{party}{x}, $ai_v{party}{y}), NAME;
\t\t\t\t} else {
\t\t\t\t\treturn;
\t\t\t\t}
\t\t\t\tAI::clear("move", "route", "mapRoute");
\t\t\t\tAI::ai_route($ai_v{party}{map}, $ai_v{party}{x}, $ai_v{party}{y}, distFromGoal => $config{followDistanceMin}, attackOnRoute => $config{'wait4party_attackOnSearch'});
\t\t\t\treturn;
\t\t\t}
\t\t# party found
\t\t} elsif ($findParty{ID} eq $_) {
\t\t\t%findParty = (); ## undef findParty!!
\t\t\tif (!$char->{'party'}{'users'}{$_}{'online'}) {
\t\t\t\tmessage TF("Party member %s is offline
", $char->{party}{users}{$_}{name}), NAME;
\t\t\t\tAI::clear("route");
\t\t\t\treturn;
\t\t\t}
\t\t\tCommands::cmdStand() if ($char->{sitting} && !$partySit{ID});
\t\t\tmessage TF("Party member %s found!
", $char->{party}{users}{$_}{name}), NAME;
\t
\t\t## party sit?
\t\t} elsif ($actor && $config{'wait4party_followSit'} && !(AI::inQueue(@notAI)) && AI::action ne "sitAuto") {
\t\t\t# Salah trigger??
\t\t\tif ($actor->{sitting} && !$partySit{ID}) {
\t\t\t\temulateCmdSit() if (!$char->{sitting});
\t\t\t\tmessage TF ("Party member %s sit
", $actor->{name}), NAME;
\t\t\t\t%partySit = ( 'ID' => $actor->{ID}, 'time' => time, 'timeout' => 10 );
\t\t\t
\t\t\t} elsif ($partySit{ID} && $actor->{ID} eq $partySit{ID} && timeOut(\%partySit)) {
\t\t\t\tif ($actor->{sitting}) {
\t\t\t\t\temulateCmdSit() if (!$char->{sitting});
\t\t\t\t\t$partySit{'time'} = time;
\t\t\t\t\t$partySit{'timeout'} = 5;
\t\t\t\t} elsif (!$actor->{sitting}) {
\t\t\t\t\tCommands::cmdStand();
\t\t\t\t\tmessage TF("Party member %s stand
", $actor->{name}), NAME;
\t\t\t\t\t%partySit = ();
\t\t\t\t\treturn;
\t\t\t\t}
\t\t\t\tif (!$char->{'party'}{'users'}{$_}{'online'}) {
\t\t\t\t\tCommands::cmdStand();
\t\t\t\t\tmessage TF("Party member %s is offline
", $actor->{name}), NAME;
\t\t\t\t\t%partySit = ();
\t\t\t\t\treturn;
\t\t\t\t}
\t\t\t}
\t\t}
\t}
\treturn;
}
sub waitCast {
\treturn unless ($config{'wait4party'}
\t && $config{'wait4party_cast'}
\t && @partyUsersID
\t && AI::action eq "route" && !AI::inQueue("attack"));
\tmy (undef,$actor) = @_;
\treturn unless existsInList($config{'wait4party_cast'}, $actor->{skill}->getName());
\tforeach (@partyUsersID) {
\t\tnext if (!$_ || $_ ne $actor->{sourceID} || $_ eq $accountID
\t\t || ($config{'wait4party_ignore'} && existsInList("$config{'wait4party_ignore'}", "$char->{'party'}{'users'}{$_}{'name'}")));
\t\tmy $wait = int($actor->{castTime} * 0.001 + 1) + 1;
\t\tmessage TF("Party member %s is casting %s, wait %d seconds
",
\t\t $char->{party}{users}{$_}{name}, $actor->{skill}->getName(), $wait), NAME;
\t\t# can't find better idea to suspend AI other than this
\t\tAI::clear("clientSuspend");
\t\tAI::ai_clientSuspend(0, $wait);
\t\treturn;
\t}
}
# Note:
# Copied from Commands::cmdSit
# change AI::ai_getAggresives() to AI::ai_getAggressives(1,1) -> react for party aggressive monster?
sub emulateCmdSit {
\t$ai_v{sitAuto_forcedBySitCommand} = 1;
\tAI::clear("move", "route", "mapRoute");
\tAI::clear("attack") unless AI::ai_getAggressives(1,1);
\trequire Task::SitStand;
\tmy $task = new Task::ErrorReport(
\t\ttask => new Task::SitStand(
\t\t\tmode => 'sit',
\t\t\tpriority => Task::USER_PRIORITY
\t\t)
\t);
\t$taskManager->add($task);
\t$ai_v{sitAuto_forceStop} = 0;
}
1;