Guest User

2011-01-11aRagexeRE | Receive/kRO/RagexeRE_0.pm

a guest
Aug 12th, 2011
532
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Perl 27.04 KB | None | 0 0
  1. #########################################################################
  2. #  OpenKore - Packet sending
  3. #  This module contains functions for sending packets to the server.
  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: 6687 $
  13. #  $Id: kRO.pm 6687 2009-04-19 19:04:25Z technologyguild $
  14. ########################################################################
  15. #
  16. # Edited for client : 2011-01-11aRagexeRE
  17. #
  18. # Korea (kRO)
  19. # The majority of private servers use eAthena, this is a clone of kRO
  20.  
  21. # this is an experimental class
  22. # this serverType is used for kRO Sakray RE
  23. # basically when we don't know where to put a new packet, we put it here and move it to the right class later
  24.  
  25. package Network::Receive::kRO::RagexeRE_0;
  26.  
  27. use strict;
  28. use base qw(Network::Receive::kRO::RagexeRE_2010_08_03a);
  29.  
  30. use Network::Receive ();
  31. use base qw(Network::Receive);
  32. use Time::HiRes qw(time usleep);
  33.  
  34. use AI;
  35. use Globals qw($char %timeout $net %config @chars $conState $conState_tries $messageSender $field);
  36. use Log qw(message warning error debug);
  37. use Translation;
  38. use Network;
  39. use Utils qw(makeCoordsDir makeCoordsXY makeCoordsFromTo);
  40.  
  41.  
  42. # from old receive.pm
  43. use Task::Wait;
  44. use Task::Function;
  45. use Task::Chained;
  46. use encoding 'utf8';
  47. use Carp::Assert;
  48. use Scalar::Util;
  49. use Exception::Class ('Network::Receive::InvalidServerType', 'Network::Receive::CreationError');
  50.  
  51. use Globals;
  52. use Actor;
  53. use Actor::You;
  54. use Actor::Player;
  55. use Actor::Monster;
  56. use Actor::Party;
  57. use Actor::Item;
  58. use Actor::Unknown;
  59. use Field;
  60. use Settings;
  61. use Log qw(message warning error debug);
  62. use FileParsers;
  63. use Interface;
  64. use Network;
  65. use Network::MessageTokenizer;
  66. use Network::Send ();
  67. use Misc;
  68. use Plugins;
  69. use Utils;
  70. use Skill;
  71. use AI;
  72. use Utils::Assert;
  73. use Utils::Exceptions;
  74. use Utils::Crypton;
  75. use Translation;
  76. use I18N qw(bytesToString);
  77.  
  78. sub new {
  79.     my ($class) = @_;
  80.     my $self = $class->SUPER::new(@_);
  81.  
  82.     my %packets = (
  83.         '006B' => ['received_characters', 'v C L3 a7 a*', [qw(len unknown1 code time1 time2 unknown2 charList)]], # -1
  84.         '0856' => ['actor_display', 'v C a4 v3 V v5 a4 v6 a4 a2 v V C2 a6 C2 v2 Z*', [qw(len object_type ID walk_speed opt1 opt2 option type hair_style weapon shield lowhead tick tophead midhead hair_color clothes_color head_dir costume guildID emblemID manner opt3 karma sex coords xSize ySize lv font name)]],
  85.         '0857' => ['actor_display', 'v C a4 v3 V v10 a4 a2 v V C2 a5 C3 v2 Z*', [qw(len object_type ID walk_speed opt1 opt2 option type hair_style weapon shield lowhead tophead midhead hair_color clothes_color head_dir guildID emblemID manner opt3 karma sex coords xSize ySize lv font name)]], # -1 # spawning
  86.         '0858' => ['actor_display', 'v C a4 v3 V v10 a4 a2 v V C2 a5 C3 v2 Z*', [qw(len object_type ID walk_speed opt1 opt2 option type hair_style weapon shield lowhead tophead midhead hair_color clothes_color head_dir guildID emblemID manner opt3 karma sex coords xSize ySize lv font name)]], # -1 # spawning
  87.         '0097' => ['private_message', 'v Z28 Z*', [qw(len privMsgUser privMsg)]],
  88.         '043D' => ['skill_post_delay', 'v V', [qw(ID time)]],
  89.         '0856' => ['actor_display', 'v C a4 v3 V v5 a4 v6 a4 a2 v V C2 a6 C2 v2 Z*', [qw(len object_type ID walk_speed opt1 opt2 option type hair_style weapon shield lowhead tick tophead midhead hair_color clothes_color head_dir costume guildID emblemID manner opt3 stance sex coords xSize ySize lv font name)]], # -1 # walking provided by try71023 TODO: costume
  90.         '0857' => ['actor_display', 'v C a4 v3 V v11 a4 a2 v V C2 a3 C3 v2 Z*', [qw(len object_type ID walk_speed opt1 opt2 option type hair_style weapon shield lowhead tophead midhead hair_color clothes_color head_dir costume guildID emblemID manner opt3 stance sex coords xSize ySize act lv font name)]], # -1 # spawning provided by try71023
  91.         '0858' => ['actor_display', 'v C a4 v3 V v11 a4 a2 v V C2 a3 C2 v2 Z*', [qw(len object_type ID walk_speed opt1 opt2 option type hair_style weapon shield lowhead tophead midhead hair_color clothes_color head_dir costume guildID emblemID manner opt3 stance sex coords xSize ySize lv font name)]], # -1 # standing provided by try71023
  92.     );
  93.     foreach my $switch (keys %packets) {
  94.         $self->{packet_list}{$switch} = $packets{$switch};
  95.     }
  96.  
  97.     return $self;
  98. }
  99.  
  100. sub received_characters_unpackString {
  101.     if ($masterServer && $masterServer->{charBlockSize} == 128) {
  102.         return 'a4 V9 v V2 v14 Z24 C8 v Z16'; # 128
  103.     } elsif ($masterServer && $masterServer->{charBlockSize} == 116) {
  104.         return 'a4 V9 v V2 v14 Z24 C6 v2'; # 116 TODO: (missing 2 last bytes)
  105.     } elsif ($masterServer && $masterServer->{charBlockSize} == 112) {
  106.         return 'a4 V9 v V2 v14 Z24 C6 v2'; # 112
  107.     } elsif ($masterServer && $masterServer->{charBlockSize} == 136) {
  108.         return 'a4 V9 v V2 v14 Z24 C6 v2 Z24'; # 112
  109.     } else {
  110.         return 'a4 V9 v17 Z24 C6 v2'; # 108
  111.     }
  112.     # a4 V9 v17 Z24 C6 v # 106
  113. }
  114.  
  115. sub received_characters {
  116.     return if ($net->getState() == Network::IN_GAME);
  117.     my ($self, $args) = @_;
  118.     message T("Received characters from Character Server\n"), "connection";
  119.     $net->setState(Network::CONNECTED_TO_LOGIN_SERVER);
  120.     undef $conState_tries;
  121.     undef @chars;
  122.  
  123.     Plugins::callHook('parseMsg/recvChars', $args->{options});
  124.     if ($args->{options} && exists $args->{options}{charServer}) {
  125.         $charServer = $args->{options}{charServer};
  126.     } else {
  127.         $charServer = $net->serverPeerHost . ":" . $net->serverPeerPort;
  128.     }
  129.  
  130.  
  131.     my $blockSize = $self->received_characters_blockSize();
  132.     for (my $i = $args->{RAW_MSG_SIZE} % $blockSize; $i < $args->{RAW_MSG_SIZE}; $i += $blockSize) {
  133.         #exp display bugfix - chobit andy 20030129
  134.         my $unpack_string = received_characters_unpackString();
  135.         my ($cID,$exp,$zeny,$jobExp,$jobLevel, $opt1, $opt2, $option, $karma, $manner, $statpt,
  136.             $hp,$maxHp,$sp,$maxSp, $walkspeed, $jobId,$hairstyle, $weapon, $level, $skillpt,$headLow, $shield,$headTop,$headMid,$hairColor,
  137.             $clothesColor,$name,$str,$agi,$vit,$int,$dex,$luk,$slot, $rename, $map) =
  138.             unpack($unpack_string, substr($args->{RAW_MSG}, $i));
  139.         $chars[$slot] = new Actor::You;
  140.         $chars[$slot]{ID} = $accountID;
  141.         $chars[$slot]{charID} = $cID;
  142.         $chars[$slot]{exp} = $exp;
  143.         $chars[$slot]{zeny} = $zeny;
  144.         $chars[$slot]{exp_job} = $jobExp;
  145.         $chars[$slot]{lv_job} = $jobLevel;
  146.         $chars[$slot]{hp} = $hp;
  147.         $chars[$slot]{hp_max} = $maxHp;
  148.         $chars[$slot]{sp} = $sp;
  149.         $chars[$slot]{sp_max} = $maxSp;
  150.         $chars[$slot]{jobID} = $jobId;
  151.         $chars[$slot]{hair_style} = $hairstyle;
  152.         $chars[$slot]{lv} = $level;
  153.         $chars[$slot]{headgear}{low} = $headLow;
  154.         $chars[$slot]{headgear}{top} = $headTop;
  155.         $chars[$slot]{headgear}{mid} = $headMid;
  156.         $chars[$slot]{hair_color} = $hairColor;
  157.         $chars[$slot]{clothes_color} = $clothesColor;
  158.         $chars[$slot]{name} = $name;
  159.         $chars[$slot]{str} = $str;
  160.         $chars[$slot]{agi} = $agi;
  161.         $chars[$slot]{vit} = $vit;
  162.         $chars[$slot]{int} = $int;
  163.         $chars[$slot]{dex} = $dex;
  164.         $chars[$slot]{luk} = $luk;
  165.         $chars[$slot]{sex} = $accountSex2;
  166.         $chars[$slot]{map} = $map;
  167.  
  168.         $chars[$slot]{nameID} = unpack("V", $chars[$slot]{ID});
  169.         $chars[$slot]{name} = bytesToString($chars[$slot]{name});
  170.     }
  171.  
  172.     # gradeA says it's supposed to send this packet here, but
  173.     # it doesn't work...
  174.     # 30 Dec 2005: it didn't work before because it wasn't sending the accountiD -> fixed (kaliwanagan)
  175.     $messageSender->sendBanCheck($accountID) if (!$net->clientAlive && $config{serverType} == 2);
  176.     if (charSelectScreen(1) == 1) {
  177.         $firstLoginMap = 1;
  178.         $startingzeny = $chars[$config{'char'}]{'zeny'} unless defined $startingzeny;
  179.         $sentWelcomeMessage = 1;
  180.     }
  181. }
  182.  
  183. sub character_name {
  184.     my ($self, $args) = @_;
  185.     my $name; # Type: String
  186.  
  187.     $name = bytesToString($args->{name});
  188.     debug "Character name received: $name\n";
  189. }
  190.  
  191. sub actor_name_received {
  192.     my ($self, $args) = @_;
  193.  
  194.     # FIXME: There is more to this packet than just party name and guild name.
  195.     # This packet is received when you leave a guild
  196.     # (with cryptic party and guild name fields, at least for now)
  197.     my $player = $playersList->getByID($args->{ID});
  198.     if (defined $player) {
  199.         # Receive names of players who are in a guild.
  200.         $player->setName(bytesToString($args->{name}));
  201.         $player->{party}{name} = bytesToString($args->{partyName});
  202.         $player->{guild}{name} = bytesToString($args->{guildName});
  203.         $player->{guild}{title} = bytesToString($args->{guildTitle});
  204.         updatePlayerNameCache($player);
  205.         debug "Player Info: $player->{name} ($player->{binID})\n", "parseMsg_presence", 2;
  206.         Plugins::callHook('charNameUpdate', {player => $player});
  207.     } else {
  208.         debug "Player Info for " . unpack("V", $args->{ID}) .
  209.             " (not on screen): " . bytesToString($args->{name}) . "\n",
  210.             "parseMsg_presence/remote", 2;
  211.     }
  212.  
  213.     my $monster = $monstersList->getByID($args->{ID});
  214.     if ($monster) {
  215.         my $name = bytesToString($args->{name});
  216.         debug "Monster Info 2: $name ($monster->{binID})\n", "parseMsg", 2;
  217.         $monster->{name_given} = $name;
  218.         if ($monsters_lut{$monster->{nameID}} eq "") {
  219.             $monster->setName($name);
  220.             $monsters_lut{$monster->{nameID}} = $name;
  221.             updateMonsterLUT(Settings::getTableFilename("monsters.txt"), $monster->{nameID}, $name);
  222.         }
  223.     }
  224.  
  225. }
  226.  
  227. sub items_nonstackable {
  228.     my ($self, $args) = @_;
  229.  
  230.     my $items = $self->{nested}->{items_nonstackable};
  231.  
  232.     if($args->{switch} eq '00A4' || # inventory
  233.        $args->{switch} eq '00A6' || # storage
  234.        $args->{switch} eq '0122'    # cart
  235.     ) {
  236.         return $items->{type1};
  237.  
  238.     } elsif ($args->{switch} eq '0295' || # inventory
  239.          $args->{switch} eq '0296' || # storage
  240.          $args->{switch} eq '0297'    # cart
  241.     ) {
  242.         return $items->{type2};
  243.  
  244.     } elsif ($args->{switch} eq '02D0' || # inventory
  245.          $args->{switch} eq '02D1' || # storage
  246.          $args->{switch} eq '02D2'    # cart
  247.     ) {
  248.         return $items->{type3};
  249.     } else {
  250.         warning "items_nonstackable: unsupported packet ($args->{switch})!\n";
  251.     }
  252. }
  253.  
  254. sub changeToInGameState {
  255.     if ($net->version() == 1) {
  256.         if ($accountID && UNIVERSAL::isa($char, 'Actor::You')) {
  257.             if ($net->getState() != Network::IN_GAME) {
  258.                 $net->setState(Network::IN_GAME);
  259.             }
  260.             return 1;
  261.         } else {
  262.             if ($net->getState() != Network::IN_GAME_BUT_UNINITIALIZED) {
  263.                 $net->setState(Network::IN_GAME_BUT_UNINITIALIZED);
  264.                 if ($config{verbose} && $messageSender && !$sentWelcomeMessage) {
  265.                     $messageSender->injectAdminMessage("Please relogin to enable X-${Settings::NAME}.");
  266.                     $sentWelcomeMessage = 1;
  267.                 }
  268.             }
  269.             return 0;
  270.         }
  271.     } else {
  272.         return 1;
  273.     }
  274. }
  275.  
  276. sub actor_display {
  277.     my ($self, $args) = @_;
  278.     return unless changeToInGameState();
  279.     my ($actor, $mustAdd);
  280.  
  281.  
  282.     #### Initialize ####
  283.  
  284.     my $nameID = unpack("V", $args->{ID});
  285.  
  286.     if ($args->{switch} eq "0086") {
  287.         # Message 0086 contains less information about the actor than other similar
  288.         # messages. So we use the existing actor information.
  289.         my $coordsArg = $args->{coords};
  290.         my $tickArg = $args->{tick};
  291.         $args = Actor::get($args->{ID})->deepCopy();
  292.         # Here we overwrite the $args data with the 0086 packet data.
  293.         $args->{switch} = "0086";
  294.         $args->{coords} = $coordsArg;
  295.         $args->{tick} = $tickArg; # lol tickcount what do we do with that? debug "tick: " . $tickArg/1000/3600/24 . "\n";
  296.     }
  297.  
  298.     my (%coordsFrom, %coordsTo);
  299.     if ($args->{switch} eq "007B" ||
  300.         $args->{switch} eq "0086" ||
  301.         $args->{switch} eq "01DA" ||
  302.         $args->{switch} eq "022C" ||
  303.         $args->{switch} eq "02EC" ||
  304.         $args->{switch} eq "07F7" ||
  305.         $args->{switch} eq "0856") {
  306.         # Actor Moved
  307.         makeCoordsFromTo(\%coordsFrom, \%coordsTo, $args->{coords}); # body dir will be calculated using the vector
  308.     } else {
  309.         # Actor Spawned/Exists
  310.         makeCoordsDir(\%coordsTo, $args->{coords}, \$args->{body_dir});
  311.         %coordsFrom = %coordsTo;
  312.     }
  313.  
  314.     # Remove actors that are located outside the map
  315.     # This may be caused by:
  316.     #  - server sending us false actors
  317.     #  - actor packets not being parsed correctly
  318.     if (defined $field && ($field->isOffMap($coordsFrom{x}, $coordsFrom{y}) || $field->isOffMap($coordsTo{x}, $coordsTo{y}))) {
  319.         warning TF("Removed actor with off map coordinates: (%d,%d)->(%d,%d), field max: (%d,%d)\n",$coordsFrom{x},$coordsFrom{y},$coordsTo{x},$coordsTo{y},$field->width(),$field->height());
  320.         return;
  321.     }
  322.  
  323.     # Remove actors with a distance greater than removeActorWithDistance. Useful for vending (so you don't spam
  324.     # too many packets in prontera and cause server lag). As a side effect, you won't be able to "see" actors
  325.     # beyond removeActorWithDistance.
  326.     if ($config{removeActorWithDistance}) {
  327.         if ((my $block_dist = blockDistance($char->{pos_to}, \%coordsTo)) > ($config{removeActorWithDistance})) {
  328.             my $nameIdTmp = unpack("V", $args->{ID});
  329.             debug "Removed out of sight actor $nameIdTmp at ($coordsTo{x}, $coordsTo{y}) (distance: $block_dist)\n";
  330.             return;
  331.         }
  332.     }
  333. =pod
  334.     # Zealotus bug
  335.     if ($args->{type} == 1200) {
  336.         open DUMP, ">> test_Zealotus.txt";
  337.         print DUMP "Zealotus: " . $nameID . "\n";
  338.         print DUMP Dumper($args);
  339.         close DUMP;
  340.     }
  341. =cut
  342.     #### Step 1: create/get the correct actor object ####
  343.     if ($jobs_lut{$args->{type}}) {
  344.         unless ($args->{type} > 6000) {
  345.             # Actor is a player
  346.             $actor = $playersList->getByID($args->{ID});
  347.             if (!defined $actor) {
  348.                 $actor = new Actor::Player();
  349.                 $actor->{appear_time} = time;
  350.                 $mustAdd = 1;
  351.             }
  352.             $actor->{nameID} = $nameID;
  353.         } else {
  354.             # Actor is a homunculus or a mercenary
  355.             $actor = $slavesList->getByID($args->{ID});
  356.             if (!defined $actor) {
  357.                 $actor = ($char->{slaves} && $char->{slaves}{$args->{ID}})
  358.                 ? $char->{slaves}{$args->{ID}} : new Actor::Slave ($args->{type});
  359.  
  360.                 $actor->{appear_time} = time;
  361.                 $mustAdd = 1;
  362.             }
  363.             $actor->{nameID} = $nameID;
  364.         }
  365.  
  366.     } elsif ($args->{type} == 45) {
  367.         # Actor is a portal
  368.         $actor = $portalsList->getByID($args->{ID});
  369.         if (!defined $actor) {
  370.             $actor = new Actor::Portal();
  371.             $actor->{appear_time} = time;
  372.             my $exists = portalExists($field->baseName, \%coordsTo);
  373.             $actor->{source}{map} = $field->baseName;
  374.             if ($exists ne "") {
  375.                 $actor->setName("$portals_lut{$exists}{source}{map} -> " . getPortalDestName($exists));
  376.             }
  377.             $mustAdd = 1;
  378.  
  379.             # Strangely enough, portals (like all other actors) have names, too.
  380.             # We _could_ send a "actor_info_request" packet to find the names of each portal,
  381.             # however I see no gain from this. (And it might even provide another way of private
  382.             # servers to auto-ban bots.)
  383.         }
  384.         $actor->{nameID} = $nameID;
  385.  
  386.     } elsif ($args->{type} >= 1000) { # FIXME: in rare cases RO uses a monster sprite for NPC's (JT_ZHERLTHSH = 0x4b0 = 1200) ==> use object_type ?
  387.         # Actor might be a monster
  388.         if ($args->{hair_style} == 0x64) {
  389.             # Actor is a pet
  390.             $actor = $petsList->getByID($args->{ID});
  391.             if (!defined $actor) {
  392.                 $actor = new Actor::Pet();
  393.                 $actor->{appear_time} = time;
  394.                 if ($monsters_lut{$args->{type}}) {
  395.                     $actor->setName($monsters_lut{$args->{type}});
  396.                 }
  397.                 $actor->{name_given} = "Unknown";
  398.                 $mustAdd = 1;
  399.  
  400.                 # Previously identified monsters could suddenly be identified as pets.
  401.                 if ($monstersList->getByID($args->{ID})) {
  402.                     $monstersList->removeByID($args->{ID});
  403.                 }
  404.             }
  405.  
  406.         } else {
  407.             # Actor really is a monster
  408.             $actor = $monstersList->getByID($args->{ID});
  409.             if (!defined $actor) {
  410.                 $actor = new Actor::Monster();
  411.                 $actor->{appear_time} = time;
  412.                 if ($monsters_lut{$args->{type}}) {
  413.                     $actor->setName($monsters_lut{$args->{type}});
  414.                 }
  415.                 $actor->{name_given} = "Unknown";
  416.                 $actor->{binType} = $args->{type};
  417.                 $mustAdd = 1;
  418.             }
  419.         }
  420.  
  421.         # Why do monsters and pets use nameID as type?
  422.         $actor->{nameID} = $args->{type};
  423.  
  424.     } else {    # ($args->{type} < 1000 && $args->{type} != 45 && !$jobs_lut{$args->{type}})
  425.         # Actor is an NPC
  426.         $actor = $npcsList->getByID($args->{ID});
  427.         if (!defined $actor) {
  428.             $actor = new Actor::NPC();
  429.             $actor->{appear_time} = time;
  430.             $mustAdd = 1;
  431.         }
  432.         $actor->{nameID} = $nameID;
  433.     }
  434.  
  435.  
  436.     #### Step 2: update actor information ####
  437.     $actor->{ID} = $args->{ID};
  438.     $actor->{jobID} = $args->{type};
  439.     $actor->{type} = $args->{type};
  440.     $actor->{lv} = $args->{lv};
  441.     $actor->{pos} = {%coordsFrom};
  442.     $actor->{pos_to} = {%coordsTo};
  443.     $actor->{walk_speed} = $args->{walk_speed} / 1000 if (exists $args->{walk_speed} && $args->{switch} ne "0086");
  444.     $actor->{time_move} = time;
  445.     $actor->{time_move_calc} = distance(\%coordsFrom, \%coordsTo) * $actor->{walk_speed};
  446.  
  447.     if (UNIVERSAL::isa($actor, "Actor::Player")) {
  448.         # None of this stuff should matter if the actor isn't a player... => does matter for a guildflag npc!
  449.  
  450.         # Interesting note about emblemID. If it is 0 (or none), the Ragnarok
  451.         # client will display "Send (Player) a guild invitation" (assuming one has
  452.         # invitation priveledges), regardless of whether or not guildID is set.
  453.         # I bet that this is yet another brilliant "feature" by GRAVITY's good programmers.
  454.         $actor->{emblemID} = $args->{emblemID} if (exists $args->{emblemID});
  455.         $actor->{guildID} = $args->{guildID} if (exists $args->{guildID});
  456.  
  457.         if (exists $args->{lowhead}) {
  458.             $actor->{headgear}{low} = $args->{lowhead};
  459.             $actor->{headgear}{mid} = $args->{midhead};
  460.             $actor->{headgear}{top} = $args->{tophead};
  461.             $actor->{weapon} = $args->{weapon};
  462.             $actor->{shield} = $args->{shield};
  463.         }
  464.  
  465.         $actor->{sex} = $args->{sex};
  466.  
  467.         if ($args->{act} == 1) {
  468.             $actor->{dead} = 1;
  469.         } elsif ($args->{act} == 2) {
  470.             $actor->{sitting} = 1;
  471.         }
  472.  
  473.         # Monsters don't have hair colors or heads to look around...
  474.         $actor->{hair_color} = $args->{hair_color} if (exists $args->{hair_color});
  475.  
  476.     } elsif (UNIVERSAL::isa($actor, "Actor::NPC") && $args->{type} == 722) { # guild flag has emblem
  477.         # odd fact: "this data can also be found in a strange place:
  478.         # (shield OR lowhead) + midhead = emblemID      (either shield or lowhead depending on the packet)
  479.         # tophead = guildID
  480.         $actor->{emblemID} = $args->{emblemID};
  481.         $actor->{guildID} = $args->{guildID};
  482.     }
  483.  
  484.     # But hair_style is used for pets, and their bodies can look different ways...
  485.     $actor->{hair_style} = $args->{hair_style} if (exists $args->{hair_style});
  486.     $actor->{look}{body} = $args->{body_dir} if (exists $args->{body_dir});
  487.     $actor->{look}{head} = $args->{head_dir} if (exists $args->{head_dir});
  488.  
  489.     # When stance is non-zero, character is bobbing as if they had just got hit,
  490.     # but the cursor also turns to a sword when they are mouse-overed.
  491.     #$actor->{stance} = $args->{stance} if (exists $args->{stance});
  492.  
  493.     # Visual effects are a set of flags (some of the packets don't have this argument)
  494.     $actor->{opt3} = $args->{opt3} if (exists $args->{opt3}); # stackable
  495.  
  496.     # Known visual effects:
  497.     # 0x0001 = Yellow tint (eg, a quicken skill)
  498.     # 0x0002 = Red tint (eg, power-thrust)
  499.     # 0x0004 = Gray tint (eg, energy coat)
  500.     # 0x0008 = Slow lightning (eg, mental strength)
  501.     # 0x0010 = Fast lightning (eg, MVP fury)
  502.     # 0x0020 = Black non-moving statue (eg, stone curse)
  503.     # 0x0040 = Translucent weapon
  504.     # 0x0080 = Translucent red sprite (eg, marionette control?)
  505.     # 0x0100 = Spaztastic weapon image (eg, mystical amplification)
  506.     # 0x0200 = Gigantic glowy sphere-thing
  507.     # 0x0400 = Translucent pink sprite (eg, marionette control?)
  508.     # 0x0800 = Glowy sprite outline (eg, assumptio)
  509.     # 0x1000 = Bright red sprite, slowly moving red lightning (eg, MVP fury?)
  510.     # 0x2000 = Vortex-type effect
  511.  
  512.     # Note that these are flags, and you can mix and match them
  513.     # Example: 0x000C (0x0008 & 0x0004) = gray tint with slow lightning
  514.  
  515. =pod
  516. typedef enum <unnamed-tag> {
  517.   SHOW_EFST_NORMAL =  0x0,
  518.   SHOW_EFST_QUICKEN =  0x1,
  519.   SHOW_EFST_OVERTHRUST =  0x2,
  520.   SHOW_EFST_ENERGYCOAT =  0x4,
  521.   SHOW_EFST_EXPLOSIONSPIRITS =  0x8,
  522.   SHOW_EFST_STEELBODY =  0x10,
  523.   SHOW_EFST_BLADESTOP =  0x20,
  524.   SHOW_EFST_AURABLADE =  0x40,
  525.   SHOW_EFST_REDBODY =  0x80,
  526.   SHOW_EFST_LIGHTBLADE =  0x100,
  527.   SHOW_EFST_MOON =  0x200,
  528.   SHOW_EFST_PINKBODY =  0x400,
  529.   SHOW_EFST_ASSUMPTIO =  0x800,
  530.   SHOW_EFST_SUN_WARM =  0x1000,
  531.   SHOW_EFST_REFLECT =  0x2000,
  532.   SHOW_EFST_BUNSIN =  0x4000,
  533.   SHOW_EFST_SOULLINK =  0x8000,
  534.   SHOW_EFST_UNDEAD =  0x10000,
  535.   SHOW_EFST_CONTRACT =  0x20000,
  536. } <unnamed-tag>;
  537. =cut
  538.  
  539.     # Save these parameters ...
  540.     $actor->{opt1} = $args->{opt1}; # nonstackable
  541.     $actor->{opt2} = $args->{opt2}; # stackable
  542.     $actor->{option} = $args->{option}; # stackable
  543.  
  544.     # And use them to set status flags.
  545.     if (setStatus($actor, $args->{opt1}, $args->{opt2}, $args->{option})) {
  546.         $mustAdd = 0;
  547.     }
  548.  
  549.  
  550.     #### Step 3: Add actor to actor list ####
  551.     if ($mustAdd) {
  552.         if (UNIVERSAL::isa($actor, "Actor::Player")) {
  553.             $playersList->add($actor);
  554.  
  555.         } elsif (UNIVERSAL::isa($actor, "Actor::Monster")) {
  556.             $monstersList->add($actor);
  557.  
  558.         } elsif (UNIVERSAL::isa($actor, "Actor::Pet")) {
  559.             $petsList->add($actor);
  560.  
  561.         } elsif (UNIVERSAL::isa($actor, "Actor::Portal")) {
  562.             $portalsList->add($actor);
  563.  
  564.         } elsif (UNIVERSAL::isa($actor, "Actor::NPC")) {
  565.             my $ID = $args->{ID};
  566.             my $location = $field->baseName . " $actor->{pos}{x} $actor->{pos}{y}";
  567.             if ($npcs_lut{$location}) {
  568.                 $actor->setName($npcs_lut{$location});
  569.             }
  570.             $npcsList->add($actor);
  571.  
  572.         } elsif (UNIVERSAL::isa($actor, "Actor::Slave")) {
  573.             $slavesList->add($actor);
  574.         }
  575.     }
  576.  
  577.  
  578.     #### Packet specific ####
  579.     if ($args->{switch} eq "0078" ||
  580.         $args->{switch} eq "01D8" ||
  581.         $args->{switch} eq "022A" ||
  582.         $args->{switch} eq "02EE" ||
  583.         $args->{switch} eq "07F9" ||
  584.         $args->{switch} eq "0857") {
  585.         # Actor Exists (standing)
  586.  
  587.         if ($actor->isa('Actor::Player')) {
  588.             my $domain = existsInList($config{friendlyAID}, unpack("V", $actor->{ID})) ? 'parseMsg_presence' : 'parseMsg_presence/player';
  589.             debug "Player Exists: " . $actor->name . " ($actor->{binID}) Level $actor->{lv} $sex_lut{$actor->{sex}} $jobs_lut{$actor->{jobID}} ($coordsFrom{x}, $coordsFrom{y})\n", $domain;
  590.  
  591.             Plugins::callHook('player', {player => $actor});  #backwards compatibility
  592.  
  593.             Plugins::callHook('player_exist', {player => $actor});
  594.  
  595.         } elsif ($actor->isa('Actor::NPC')) {
  596.             message TF("NPC Exists: %s (%d, %d) (ID %d) - (%d)\n", $actor->name, $actor->{pos_to}{x}, $actor->{pos_to}{y}, $actor->{nameID}, $actor->{binID}), "parseMsg_presence", 1;
  597.  
  598.         } elsif ($actor->isa('Actor::Portal')) {
  599.             message TF("Portal Exists: %s (%s, %s) - (%s)\n", $actor->name, $actor->{pos_to}{x}, $actor->{pos_to}{y}, $actor->{binID}), "portals", 1;
  600.  
  601.         } elsif ($actor->isa('Actor::Monster')) {
  602.             debug sprintf("Monster Exists: %s (%d)\n", $actor->name, $actor->{binID}), "parseMsg_presence", 1;
  603.  
  604.         } elsif ($actor->isa('Actor::Pet')) {
  605.             debug sprintf("Pet Exists: %s (%d)\n", $actor->name, $actor->{binID}), "parseMsg_presence", 1;
  606.  
  607.         } elsif ($actor->isa('Actor::Slave')) {
  608.             debug sprintf("Slave Exists: %s (%d)\n", $actor->name, $actor->{binID}), "parseMsg_presence", 1;
  609.  
  610.         } else {
  611.             debug sprintf("Unknown Actor Exists: %s (%d)\n", $actor->name, $actor->{binID}), "parseMsg_presence", 1;
  612.         }
  613.  
  614.     } elsif ($args->{switch} eq "0079" ||
  615.         $args->{switch} eq "01DB" ||
  616.         $args->{switch} eq "022B" ||
  617.         $args->{switch} eq "02ED" ||
  618.         $args->{switch} eq "01D9" ||
  619.         $args->{switch} eq "07F8" ||
  620.         $args->{switch} eq "0858") {
  621.         # Actor Connected (new)
  622.  
  623.         if ($actor->isa('Actor::Player')) {
  624.             my $domain = existsInList($config{friendlyAID}, unpack("V", $args->{ID})) ? 'parseMsg_presence' : 'parseMsg_presence/player';
  625.             debug "Player Connected: ".$actor->name." ($actor->{binID}) Level $args->{lv} $sex_lut{$actor->{sex}} $jobs_lut{$actor->{jobID}} ($coordsTo{x}, $coordsTo{y})\n", $domain;
  626.  
  627.             Plugins::callHook('player', {player => $actor});  #backwards compatibailty
  628.  
  629.             Plugins::callHook('player_connected', {player => $actor});
  630.         } else {
  631.             debug "Unknown Connected: $args->{type} - ", "parseMsg";
  632.         }
  633.  
  634.     } elsif ($args->{switch} eq "007B" ||
  635.         $args->{switch} eq "0086" ||
  636.         $args->{switch} eq "01DA" ||
  637.         $args->{switch} eq "022C" ||
  638.         $args->{switch} eq "02EC" ||
  639.         $args->{switch} eq "07F7" ||
  640.         $args->{switch} eq "0856") {
  641.         # Actor Moved
  642.  
  643.         # Correct the direction in which they're looking
  644.         my %vec;
  645.         getVector(\%vec, \%coordsTo, \%coordsFrom);
  646.         my $direction = int sprintf("%.0f", (360 - vectorToDegree(\%vec)) / 45);
  647.  
  648.         $actor->{look}{body} = $direction;
  649.         $actor->{look}{head} = 0;
  650.  
  651.         if ($actor->isa('Actor::Player')) {
  652.             debug "Player Moved: " . $actor->name . " ($actor->{binID}) Level $actor->{lv} $sex_lut{$actor->{sex}} $jobs_lut{$actor->{jobID}} - ($coordsFrom{x}, $coordsFrom{y}) -> ($coordsTo{x}, $coordsTo{y})\n", "parseMsg";
  653.         } elsif ($actor->isa('Actor::Monster')) {
  654.             debug "Monster Moved: " . $actor->nameIdx . " - ($coordsFrom{x}, $coordsFrom{y}) -> ($coordsTo{x}, $coordsTo{y})\n", "parseMsg";
  655.         } elsif ($actor->isa('Actor::Pet')) {
  656.             debug "Pet Moved: " . $actor->nameIdx . " - ($coordsFrom{x}, $coordsFrom{y}) -> ($coordsTo{x}, $coordsTo{y})\n", "parseMsg";
  657.         } elsif ($actor->isa('Actor::Slave')) {
  658.             debug "Slave Moved: " . $actor->nameIdx . " - ($coordsFrom{x}, $coordsFrom{y}) -> ($coordsTo{x}, $coordsTo{y})\n", "parseMsg";
  659.         } elsif ($actor->isa('Actor::Portal')) {
  660.             # This can never happen of course.
  661.             debug "Portal Moved: " . $actor->nameIdx . " - ($coordsFrom{x}, $coordsFrom{y}) -> ($coordsTo{x}, $coordsTo{y})\n", "parseMsg";
  662.         } elsif ($actor->isa('Actor::NPC')) {
  663.             # Neither can this.
  664.             debug "NPC Moved: " . $actor->nameIdx . " - ($coordsFrom{x}, $coordsFrom{y}) -> ($coordsTo{x}, $coordsTo{y})\n", "parseMsg";
  665.         } else {
  666.             debug "Unknown Actor Moved: " . $actor->nameIdx . " - ($coordsFrom{x}, $coordsFrom{y}) -> ($coordsTo{x}, $coordsTo{y})\n", "parseMsg";
  667.         }
  668.  
  669.     } elsif ($args->{switch} eq "007C") {
  670.         # Actor Spawned
  671.         if ($actor->isa('Actor::Player')) {
  672.             debug "Player Spawned: " . $actor->nameIdx . " $sex_lut{$actor->{sex}} $jobs_lut{$actor->{jobID}}\n", "parseMsg";
  673.         } elsif ($actor->isa('Actor::Monster')) {
  674.             debug "Monster Spawned: " . $actor->nameIdx . "\n", "parseMsg";
  675.         } elsif ($actor->isa('Actor::Pet')) {
  676.             debug "Pet Spawned: " . $actor->nameIdx . "\n", "parseMsg";
  677.         } elsif ($actor->isa('Actor::Slave')) {
  678.             debug "Slave Spawned: " . $actor->nameIdx . " $jobs_lut{$actor->{jobID}}\n", "parseMsg";
  679.         } elsif ($actor->isa('Actor::Portal')) {
  680.             # Can this happen?
  681.             debug "Portal Spawned: " . $actor->nameIdx . "\n", "parseMsg";
  682.         } elsif ($actor->isa('NPC')) {
  683.             debug "NPC Spawned: " . $actor->nameIdx . "\n", "parseMsg";
  684.         } else {
  685.             debug "Unknown Spawned: " . $actor->nameIdx . "\n", "parseMsg";
  686.         }
  687.     }
  688. }
  689.  
  690. sub skill_post_delay {
  691.     my ($self, $args) = @_;
  692.    
  693.     my $skillName = (new Skill(idn => $args->{ID}))->getName;
  694.     my $status = defined $statusName{'EFST_DELAY'} ? $statusName{'EFST_DELAY'} : ' Delay';
  695.    
  696.     $char->setStatus($skillName.$status, 1, $args->{time});
  697. }
  698.  
  699. =pod
  700. packet_ver: 26
  701. 0x0436,19,wanttoconnection,2:6:10:14:18
  702. 0x035f,5,walktoxy,2
  703. 0x0360,6,ticksend,2
  704. 0x0361,5,changedir,2:4
  705. 0x0362,6,takeitem,2
  706. 0x0363,6,dropitem,2:4
  707. 0x0364,8,movetokafra,2:4
  708. 0x0365,8,movefromkafra,2:4
  709. 0x0366,10,useskilltopos,2:4:6:8
  710. 0x0367,90,useskilltoposinfo,2:4:6:8:10
  711. 0x0368,6,getcharnamerequest,2
  712. 0x0369,6,solvecharname,2
  713. 0x0856,-1
  714. 0x0857,-1
  715. 0x0858,-1
  716. 0x0859,-1
  717. =cut
  718. 1;
Advertisement
Add Comment
Please, Sign In to add comment