FollowActor.pm.svn-base
上传用户:market2
上传日期:2018-11-18
资源大小:18786k
文件大小:7k
源码类别:

外挂编程

开发平台:

Windows_Unix

  1. #########################################################################
  2. #  OpenKore - Actor following task
  3. #  Copyright (c) 2006 OpenKore Team
  4. #
  5. #  This software is open source, licensed under the GNU General Public
  6. #  License, version 2.
  7. #  Basically, this means that you're allowed to modify and distribute
  8. #  this software. However, if you distribute modified versions, you MUST
  9. #  also distribute the source code.
  10. #  See http://www.gnu.org/licenses/gpl.html for the full license.
  11. #########################################################################
  12. # This task allows you to follow an actor (the target). This task will
  13. # continue infinitely until you stop it, or until the target has
  14. # disappeared from our sight.
  15. #
  16. # Note that this task does not handle situations where the target has entered
  17. # a portal. It also does not look up the target's coordinate using the party
  18. # list, of the target is a player who's in the party. This task is specialized
  19. # in following a single actor within the same map. More advanced follow
  20. # abilities should be implemented by a different task (TODO: write such a
  21. # task).
  22. package Task::FollowActor;
  23. use strict;
  24. use Time::HiRes qw(time);
  25. use Scalar::Util;
  26. use Modules 'register';
  27. use Globals;
  28. use Task;
  29. use base qw(Task);
  30. use Task::Route;
  31. use Network;
  32. use Log qw(debug);
  33. use Actor;
  34. use Utils qw(timeOut distance getVector moveAlongVector calcPosition);
  35. use Utils::Exceptions;
  36. ##
  37. # Task::FollowActor->new(options...)
  38. #
  39. # Create a new Task::FollowActor object. The following options are allowed:
  40. # `l
  41. # - All options allowed for Task->new() except 'mutexes'.
  42. # - actor (required) - The Actor to follow.
  43. # - actorList (required) - The ActorList which contains the actor object.
  44. #                          This is used to check whether the actor is still on screen.
  45. # - maxDistance - The maximum distance that the actor may be away from you.
  46. # - minDistance - If the distance to the actor is greater than maxDistance, then walk
  47. #                 to the actor until you're within distance minDistance.
  48. # `l`
  49. sub new {
  50. my $class = shift;
  51. my %args = @_;
  52. my $self = $class->SUPER::new(@_, mutexes => ['movement']);
  53. if (!$args{actor} || !$args{actorList}) {
  54. ArgumentException->throw(error => "Invalid arguments.");
  55. }
  56. $self->{actorID} = $args{actor}{ID};
  57. $self->{actorList} = $args{actorList};
  58. $self->{minDistance} = $args{minDistance} || 1.42; # sqrt(2)
  59. $self->{maxDistance} = $args{maxDistance} || 1.42; # sqrt(2)
  60. $self->{probe}{timeout} = 0.33;
  61. $self->{wait_after_login}{timeout} = 2;
  62. my @holder = ($self);
  63. Scalar::Util::weaken($holder[0]);
  64. $self->{hook} = Plugins::addHook('Network::stateChanged', &networkStateChanged, @holder);
  65. return $self;
  66. }
  67. sub DESTROY {
  68. my ($self) = @_;
  69. Plugins::delHook($self->{hook});
  70. }
  71. sub iterate {
  72. my ($self) = @_;
  73. return if (!timeOut($self->{probe}));
  74. if ($net->getState() != Network::IN_GAME) {
  75. # We got disconnected, so re-lookup the target Actor object when
  76. # we're reconnected.
  77. delete $self->{actor};
  78. } elsif (timeOut($self->{wait_after_login}) && $char->{pos_to} && defined $char->{pos_to}{x}) {
  79. my $actor = $self->{actor};
  80. if (!$actor) {
  81. $actor = $self->{actor} = $self->{actorList}->getByID($self->{actorID});
  82. if (!$actor) {
  83. # Target is not on screen and we don't know where it went.
  84. debug "FollowActor - we lost the targetn", "followActor";
  85. $self->setDone();
  86. }
  87. }
  88. if ($actor->{dead} || $actor->{disappeared} || $actor->{teleported} || $actor->{disconnected}) {
  89. # We know the target is gone.
  90. debug "FollowActor - target is gonen", "followActor";
  91. $self->setDone();
  92. } elsif ($actor->{pos_to} && defined $actor->{pos_to}{x}) {
  93. # Target is still there.
  94. $self->processFollow();
  95. }
  96. }
  97. $self->{probe}{time} = time;
  98. }
  99. sub processFollow {
  100. my ($self) = @_;
  101. my $actor = $self->{actor};
  102. # Check whether the target is within acceptable distance limits.
  103. my $distance = distance($char->{pos_to}, $actor->{pos_to});
  104. if ($distance > $self->{maxDistance}) {
  105. $self->{withinLimits} = 0;
  106. # Find an interception point, and go there.
  107. my $interceptPoint = intercept($char, $actor, $actor->{walk_speed});
  108. if ($self->{task}) {
  109. # If we're already walking, check whether we need to adjust the path.
  110. my $currentDestination = $self->{task}->destCoords();
  111. if (distance($interceptPoint, $currentDestination) > 1.42) {
  112. debug "FollowActor - readjusting existing routen", "followActor";
  113. $self->{task}->stop();
  114. delete $self->{task};
  115. }
  116. }
  117. if (!$self->{task}) {
  118. my $task = $self->{task} = new Task::Route(
  119. x => $interceptPoint->{x},
  120. y => $interceptPoint->{y},
  121. maxTime => 5);
  122. $task->activate();
  123. $self->setMutexes('movement');
  124. }
  125. $self->{task}->iterate();
  126. if ($self->{task}->getStatus() == Task::DONE) {
  127. delete $self->{task};
  128. $self->setMutexes();
  129. }
  130. } else {
  131. $self->{withinLimits} = 1;
  132. if ($self->{task}) {
  133. $self->{task}->stop();
  134. delete $self->{task};
  135. $self->setMutexes();
  136. }
  137. }
  138. }
  139. sub networkStateChanged {
  140. my (undef, undef, $holder) = @_;
  141. if ($net->getState() == Network::IN_GAME) {
  142. # After logging into the game, wait some time for
  143. # actors to appear on screen.
  144. my $self = $holder->[0];
  145. $self->{wait_after_login}{time} = time;
  146. }
  147. }
  148. ##
  149. # boolean $Task_FollowActor->withinLimits()
  150. #
  151. # Check whether the distance to the actor to be followed is within the
  152. # distance limits, as given to the constructor.
  153. sub withinLimits {
  154. return $_[0]->{withinLimits};
  155. }
  156. # Hash* intercept(Actor actorA, Actor actorB, int variance)
  157. #
  158. # Find an interception point which allows actor A to intercept actor B.
  159. sub intercept {
  160. my ($actorA, $actorB, $variance) = @_;
  161. my $aPos = calcPosition($actorA);
  162. my $bPos = calcPosition($actorB);
  163. my %actorB_vec;
  164. getVector(%actorB_vec, $actorB->{pos_to}, $bPos);
  165. my $maxDist = distance($bPos, $actorB->{pos_to});
  166. for (my $dist = 1; $dist < $maxDist; $dist++) {
  167. my %try;
  168. moveAlongVector(%try, $bPos, %actorB_vec, $dist);
  169. my $actorA_to_try_dist = distance($aPos, %try);
  170. my $aWalkTime = ($actorA->{walk_speed}) ? $actorA_to_try_dist / $actorA->{walk_speed} : 0;
  171. my $bWalkTime = ($actorB->{walk_speed}) ? $dist / $actorB->{walk_speed} : 0;
  172. #printf("tryX = %.2f, tryY = %.2f, aTime = %.2f, bTime = %.2fn",
  173. # $try{x}, $try{y}, $aWalkTime, $bWalkTime);
  174. if ($aWalkTime < $bWalkTime) {
  175. # Add a small variance to cope with network lag.
  176. $dist += $variance;
  177. $dist = $maxDist if ($dist > $maxDist);
  178. moveAlongVector(%try, $bPos, %actorB_vec, $dist);
  179. $try{x} = int $try{x};
  180. $try{y} = int $try{y};
  181. return %try;
  182. }
  183. }
  184. return $actorB->{pos_to};
  185. }
  186. # sub testIntercept {
  187. #  my $a = new Actor('Player');
  188. #  $a->{pos}    = { x => 12, y => 1 };
  189. #  $a->{pos_to} = { x => 12, y => 1 };
  190. #  $a->{walk_speed} = 1;
  191. #  $a->{time_move}  = time;
  192. #  my $b = new Actor('Monster');
  193. #  $b->{pos}    = { x => 16, y => 4};
  194. #  $b->{pos_to} = { x => 1,  y => 6 };
  195. #  $b->{walk_speed} = 1;
  196. #  $b->{time_move}  = time;
  197. #  $b->{time_move_calc} = distance($b->{pos}, $b->{pos_to}) * $b->{walk_speed};
  198. #  my $ret = intercept($a, $b, $b->{walk_speed});
  199. #  print "x = $ret->{x}n";
  200. #  print "y = $ret->{y}n";
  201. # }
  202. # testIntercept();
  203. 1;