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

外挂编程

开发平台:

Windows_Unix

  1. #########################################################################
  2. #  OpenKore - Item object
  3. #  Copyright (c) 2005, 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. #  $Revision$
  13. #  $Id$
  14. #
  15. #########################################################################
  16. ##
  17. # MODULE DESCRIPTION: Inventory item object
  18. #
  19. # All members in $char->inventory are of the Actor::Item class.
  20. package Actor::Item;
  21. use strict;
  22. use Carp::Assert;
  23. use Scalar::Util;
  24. use Time::HiRes qw(time);
  25. use Globals;
  26. use Actor;
  27. use base qw(Actor);
  28. use Utils;
  29. use Log qw(message error warning debug);
  30. use Network::Send ();
  31. use AI;
  32. use Translation;
  33. use overload '""' => &_toString;
  34. use overload '==' => &_isis;
  35. use overload '!=' => &_not_is;
  36. use overload 'eq' => &_eq;
  37. use overload 'ne' => &_ne;
  38. sub _toString {
  39. return $_[0]->nameString();
  40. }
  41. sub _isis {
  42. return Scalar::Util::refaddr($_[0]) == Scalar::Util::refaddr($_[1]);
  43. }
  44. sub _not_is {
  45. return !&_isis;
  46. }
  47. sub _eq {
  48. return UNIVERSAL::isa($_[0], 'Actor::Item') && UNIVERSAL::isa($_[1], 'Actor::Item')
  49. && $_[0]->{nameID} == $_[1]->{nameID};
  50. }
  51. sub _ne {
  52. return !&_eq;
  53. }
  54. our @slots = qw(
  55. topHead midHead lowHead
  56. leftHand rightHand
  57. robe armor shoes
  58. leftAccessory rightAccessory
  59. arrow
  60. );
  61. ##############################
  62. ### CATEGORY: Constructor
  63. ##############################
  64. ##
  65. # Actor::Item Actor::Item->new()
  66. #
  67. # Creates a new Actor::Item object.
  68. sub new {
  69. my $class = $_[0];
  70. my $self = $class->SUPER::new('Item');
  71. $self->{name} = 'Uninitialized Item';
  72. $self->{index} = 0;
  73. $self->{amount} = 0;
  74. $self->{type} = 0;
  75. $self->{equipped} = 0;
  76. $self->{identified} = 0;
  77. $self->{nameID} = 0;
  78. $self->{invIndex} = 0;
  79. return $self;
  80. }
  81. ##############################
  82. ### CATEGORY: Class Methods
  83. ##############################
  84. ##
  85. # Actor::Item::get(name, skipIndex, notEquipped)
  86. # item: can be either an object itself, an ID or a name.
  87. # skipIndex: tells this function to not select a certain item (used for getting another item with the same name).
  88. # notEquipped: 1 = not equipped item; 0 = equipped item; undef = all item
  89. # Returns: an Actor::Item object, or undef if not found or parameters not matched.
  90. #
  91. # Find an item in the inventory, based on the search criteria specified by the parameters.
  92. #
  93. # See also: Actor::Item::getMultiple()
  94. sub get {
  95. my ($name, $skipIndex, $notEquipped) = @_;
  96. return undef if (!defined $name);
  97. return $name if UNIVERSAL::isa($name, 'Actor::Item');
  98. # user supplied an inventory index
  99. if ($name =~ /^d+$/) {
  100. return $char->inventory->get($name);
  101. # user supplied an item name
  102. } else {
  103. my $condition;
  104. if ($notEquipped) {
  105. # making sure that $skipIndex is defined:  when perl is expecting a number and gets an undef instead, it will transform that value into 0, wich is a possible invIndex here
  106. $condition = sub { ($_[0]->{invIndex} != $skipIndex || !defined $skipIndex) && $_[0]->{name} eq $name && !$_[0]->{equipped} };
  107. } elsif (!$notEquipped && defined($notEquipped)) {
  108. $condition = sub { ($_[0]->{invIndex} != $skipIndex || !defined $skipIndex) && $_[0]->{name} eq $name && $_[0]->{equipped} };
  109. } else {
  110. $condition = sub { ($_[0]->{invIndex} != $skipIndex || !defined $skipIndex) && $_[0]->{name} eq $name };
  111. }
  112. return $char->inventory->getByCondition($condition);
  113. }
  114. }
  115. ##
  116. # Actor::Item::getMultiple(searchPattern)
  117. # searchString: a search pattern.
  118. # Returns: an array of Actor::Item objects.
  119. #
  120. # Select one or more items in the inventory. $searchPattern has the following syntax:
  121. # <pre>index1,index2,...,indexN</pre>
  122. # You can also use '-' to indicate a range, like:
  123. # <pre>1-5,7,9</pre>
  124. sub getMultiple {
  125. my @temp = split /,+/, $_[0];
  126. my @items;
  127. foreach my $index (@temp) {
  128. if ($index =~ /(d+)-(d+)/) {
  129. for ($1..$2) {
  130. my $item = Actor::Item::get($_);
  131. push(@items, $item) if ($item);
  132. }
  133. } else {
  134. my $item = Actor::Item::get($index);
  135. push @items, $item if ($item);
  136. }
  137. }
  138. return @items;
  139. }
  140. ##
  141. # Actor::Item::bulkEquip(list)
  142. # list: a hash containing slot => item, where slot is "leftHand" or "rightHand", and item is an item identifier as recognized by Actor::Item::get().
  143. #
  144. # Equip many items in one batch.
  145. #
  146. # Example:
  147. # %list = (leftHand => 'Katar', rightHand => 10);
  148. # Actor::Item::bulkEquip(%list);
  149. sub bulkEquip {
  150. my $list = $_[0];
  151. return unless $list && %{$list};
  152. my ($item, $rightHand, $rightAccessory);
  153. foreach (keys %{$list}) {
  154. error "Wrong Itemslot specified: $_n",'Actor::Item' if (!exists $equipSlot_rlut{$_});
  155. my $skipIndex;
  156. $skipIndex = $rightHand if ($_ eq 'leftHand');
  157. $skipIndex = $rightAccessory if ($_ eq 'leftAccessory');
  158. $item = Actor::Item::get($list->{$_}, $skipIndex, 1);
  159. next unless ($item && $char->{equipment} && ($char->{equipment}{$_}{name} ne $item->{name}));
  160. $item->equipInSlot($_);
  161. $rightHand = $item->{invIndex} if ($_ eq 'rightHand');
  162. $rightAccessory = $item->{invIndex} if ($_ eq 'rightAccessory');
  163. }
  164. }
  165. ##
  166. # Actor::Item::scanConfigAndEquip(prefix)
  167. #
  168. # prefix: is used to scan for slots
  169. #
  170. # e.g.:
  171. # <pre>
  172. # $prefix = equipAuto_1
  173. # will equip
  174. # equipAuto_1_leftHand Sword
  175. # </pre>
  176. sub scanConfigAndEquip {
  177. my $prefix = shift;
  178. my %eq_list;
  179. debug "Scanning config and equipping: $prefixn";
  180. foreach my $slot (%equipSlot_lut) {
  181. if ($config{"${prefix}_$slot"}){
  182. $eq_list{$slot} = $config{"${prefix}_$slot"};
  183. }
  184. }
  185. bulkEquip(%eq_list) if (%eq_list);
  186. }
  187. ##
  188. # Actor::Item::scanConfigAndCheck(prefix)
  189. # prefix: is used to scan for slots.
  190. # Returns: whether there is a item that needs to be equipped.
  191. #
  192. # Similiar to Actor::Item::scanConfigAndEquip() but only checks if a Actor::Item needs to be equipped.
  193. sub scanConfigAndCheck {
  194. my $prefix = $_[0];
  195. return 0 unless $prefix;
  196. my $count = 0;
  197. foreach my $slot (values %equipSlot_lut) {
  198. if (exists $config{"${prefix}_$slot"}){
  199. my $item = Actor::Item::get($config{"${prefix}_$slot"}, undef, 1);
  200. $count++ if ($item && $char->{equipment} && ($char->{equipment}{$slot}{name} ne $item->{name}));
  201. }
  202. }
  203. return $count;
  204. }
  205. ##
  206. # Actor::Item::queueEquip(count)
  207. # count: how many items need to be equipped.
  208. #
  209. # Queues equip sequence.
  210. sub queueEquip {
  211. my $count = shift;
  212. return unless $count;
  213. $ai_v{temp}{waitForEquip} += $count;
  214. AI::queue('equip') unless AI::action eq 'equip';
  215. $timeout{ai_equip_giveup}{time} = time;
  216. }
  217. ##########
  218. # Maybe this Method is not needed.
  219. sub UnEquipByType {
  220. my $type = shift;
  221. for (my $i = 0; $i < @{$char->{'inventory'}}; $i++) {
  222. next if (!%{$char->{'inventory'}[$i]});
  223. if ($char->{'inventory'}[$i]{'equipped'} & $type) {
  224. $char->{'inventory'}[$i]->unequip();
  225. return $i;
  226. }
  227. }
  228. return undef;
  229. }
  230. ################################
  231. ### CATEGORY: Public Members
  232. ################################
  233. ##
  234. # String $ActorItem->{name}
  235. # Invariant: defined(value)
  236. #
  237. # The name for this item.
  238. ##
  239. # int $ActorItem->{index}
  240. # Invariant: value >= 0
  241. #
  242. # The index of this item in the inventory, as stored on the RO server. It is usually
  243. # used when sending item-related commands (such as 'use this item' or 'drop this item')
  244. # to the RO server.
  245. # This index does not necessarily equals the inventory index, as stored by OpenKore.
  246. #
  247. # See also: $ActorItem->{invIndex}
  248. ##
  249. # int $ActorItem->{amount}
  250. # Invariant: value >= 0
  251. #
  252. # The amount of this item in the inventory.
  253. ##
  254. # int $ActorItem->{type}
  255. # Invariant: value >= 0
  256. #
  257. # The item type (usable, unusable, armor, etc.), as defined by itemtypes.txt.
  258. ##
  259. # boolean $ActorItem->{equipped}
  260. #
  261. # Whether this item is currently equipped.
  262. ##
  263. # boolean $ActorItem->{identified}
  264. #
  265. # Whether this item is identified.
  266. ##
  267. # int $ActorItem->{nameID}
  268. # Invariant: value >= 0
  269. #
  270. # The ID of this item. This ID is unique for each item class.
  271. # Use this in combination with %items_lut to retrieve the item name.
  272. ##
  273. # int $ActorItem->{invIndex}
  274. #
  275. # The index of this item in the inventory data structure, as stored by OpenKore.
  276. # This index does not necessarily correspond with the index as stored by the RO server.
  277. #
  278. # See also: $ActorItem->{index}
  279. ##
  280. # Bytes $ActorItem->{takenBy}
  281. #
  282. # The ID of the actor who has taken this item. This field is set when an
  283. # actor picks up an item.
  284. ################################
  285. ### CATEGORY: Public Methods
  286. ################################
  287. ##
  288. # String $ActorItem->nameString()
  289. # Returns: the item name, in the form of "My Item [number of slots]".
  290. sub nameString {
  291. my $self = shift;
  292. return "$self->{name} ($self->{invIndex})";
  293. }
  294. ##
  295. # $ActorItem->equippedInSlot(slot)
  296. # slot: slot to check
  297. # Returns: wheter item is equipped in $slot
  298. sub equippedInSlot {
  299. my ($self, $slot) = @_;
  300. return ($self->{equipped} & $equipSlot_rlut{$slot});
  301. }
  302. #sub equippable {
  303. # my $self = shift;
  304. #}
  305. ##
  306. # void $ActorItem->equip()
  307. #
  308. # Will simply equip the item. If you want more control, use $item->equipInSlot()
  309. sub equip {
  310. my $self = shift;
  311. return 1 if $self->{equipped};
  312. $messageSender->sendEquip($self->{index}, $self->{type_equip});
  313. queueEquip(1);
  314. return 0;
  315. }
  316. ##
  317. # void $ActorItem->unequip()
  318. #
  319. # Unequips the item.
  320. sub unequip {
  321. my $self = shift;
  322. return 1 unless $self->{equipped};
  323. $messageSender->sendUnequip($self->{index});
  324. return 0;
  325. }
  326. ##
  327. # void $ActorItem->use([Bytes target])
  328. # target: ID of the target, if not set then $accountID will be used.
  329. #
  330. # Uses this item on yourself or on a target.
  331. sub use {
  332. my $self = shift;
  333. my $target = shift;
  334. return 0 unless $self->{type} <= 2;
  335. if (!$target || $target == $accountID) {
  336. $messageSender->sendItemUse($self->{index}, $accountID);
  337. }
  338. else {
  339. $messageSender->sendItemUse($self->{index}, $target);
  340. }
  341. return 1;
  342. }
  343. ##
  344. # void $ActorItem->equipInSlot(slot dontqueue)
  345. # slot: where item should be equipped.
  346. #
  347. # Equips item in $slot.
  348. sub equipInSlot {
  349. my ($self,$slot) = @_;
  350. unless (defined $equipSlot_rlut{$slot}) {
  351. error TF("Wrong equip slot specifiedn");
  352. return 1;
  353. }
  354. # return if Item is already equipped
  355. if ($char->{equipment}{$slot} && $char->{equipment}{$slot}{name} eq $self->{name}) {
  356. error TF("Inventory Item: %s is already equipped in slot: %sn", $self->{name}, $slot);
  357. return 1;
  358. }
  359. $messageSender->sendEquip($self->{index}, $equipSlot_rlut{$slot});
  360. queueEquip(1);
  361. return 0;
  362. }
  363. ##
  364. # void $ActorItem->unequipFromSlot(slot dontqueue)
  365. # slot: where item should be unequipped.
  366. #
  367. # Unequips item from $slot.
  368. sub unequipFromSlot {
  369. my ($self,$slot) = @_;
  370. unless (defined $equipSlot_rlut{$slot}) {
  371. error TF("Wrong equip slot specifiedn");
  372. return 1;
  373. }
  374. # return if no Item is equiped in this slot or if the item name does not match the given one
  375. if (!$char->{equipment}{$slot} || $char->{equipment}{$slot}{name} ne $self->{name}) {
  376. error TF("No such equipped Inventory Item: %s in slot: %sn", $self->{name}, $slot);
  377. return 1;
  378. }
  379. $messageSender->sendUnequip($self->{index});
  380. return 0;
  381. }
  382. 1;