Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #########################################################################
- # OpenKore - Packet sending
- # This module contains functions for sending packets to the server.
- #
- # This software is open source, licensed under the GNU General Public
- # License, version 2.
- # Basically, this means that you're allowed to modify and distribute
- # this software. However, if you distribute modified versions, you MUST
- # also distribute the source code.
- # See http://www.gnu.org/licenses/gpl.html for the full license.
- #
- # $Revision: 6687 $
- # $Id: kRO.pm 6687 2009-04-19 19:04:25Z technologyguild $
- ########################################################################
- #
- # Edited for client : 2011-01-11aRagexeRE
- #
- # Korea (kRO)
- # The majority of private servers use eAthena, this is a clone of kRO
- # this is an experimental class
- # this serverType is used for kRO Sakray RE
- # basically when we don't know where to put a new packet, we put it here and move it to the right class later
- package Network::Receive::kRO::RagexeRE_0;
- use strict;
- use base qw(Network::Receive::kRO::RagexeRE_2010_08_03a);
- use Network::Receive ();
- use base qw(Network::Receive);
- use Time::HiRes qw(time usleep);
- use AI;
- use Globals qw($char %timeout $net %config @chars $conState $conState_tries $messageSender $field);
- use Log qw(message warning error debug);
- use Translation;
- use Network;
- use Utils qw(makeCoordsDir makeCoordsXY makeCoordsFromTo);
- # from old receive.pm
- use Task::Wait;
- use Task::Function;
- use Task::Chained;
- use encoding 'utf8';
- use Carp::Assert;
- use Scalar::Util;
- use Exception::Class ('Network::Receive::InvalidServerType', 'Network::Receive::CreationError');
- use Globals;
- use Actor;
- use Actor::You;
- use Actor::Player;
- use Actor::Monster;
- use Actor::Party;
- use Actor::Item;
- use Actor::Unknown;
- use Field;
- use Settings;
- use Log qw(message warning error debug);
- use FileParsers;
- use Interface;
- use Network;
- use Network::MessageTokenizer;
- use Network::Send ();
- use Misc;
- use Plugins;
- use Utils;
- use Skill;
- use AI;
- use Utils::Assert;
- use Utils::Exceptions;
- use Utils::Crypton;
- use Translation;
- use I18N qw(bytesToString);
- sub new {
- my ($class) = @_;
- my $self = $class->SUPER::new(@_);
- my %packets = (
- '006B' => ['received_characters', 'v C L3 a7 a*', [qw(len unknown1 code time1 time2 unknown2 charList)]], # -1
- '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)]],
- '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
- '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
- '0097' => ['private_message', 'v Z28 Z*', [qw(len privMsgUser privMsg)]],
- '043D' => ['skill_post_delay', 'v V', [qw(ID time)]],
- '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
- '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
- '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
- );
- foreach my $switch (keys %packets) {
- $self->{packet_list}{$switch} = $packets{$switch};
- }
- return $self;
- }
- sub received_characters_unpackString {
- if ($masterServer && $masterServer->{charBlockSize} == 128) {
- return 'a4 V9 v V2 v14 Z24 C8 v Z16'; # 128
- } elsif ($masterServer && $masterServer->{charBlockSize} == 116) {
- return 'a4 V9 v V2 v14 Z24 C6 v2'; # 116 TODO: (missing 2 last bytes)
- } elsif ($masterServer && $masterServer->{charBlockSize} == 112) {
- return 'a4 V9 v V2 v14 Z24 C6 v2'; # 112
- } elsif ($masterServer && $masterServer->{charBlockSize} == 136) {
- return 'a4 V9 v V2 v14 Z24 C6 v2 Z24'; # 112
- } else {
- return 'a4 V9 v17 Z24 C6 v2'; # 108
- }
- # a4 V9 v17 Z24 C6 v # 106
- }
- sub received_characters {
- return if ($net->getState() == Network::IN_GAME);
- my ($self, $args) = @_;
- message T("Received characters from Character Server\n"), "connection";
- $net->setState(Network::CONNECTED_TO_LOGIN_SERVER);
- undef $conState_tries;
- undef @chars;
- Plugins::callHook('parseMsg/recvChars', $args->{options});
- if ($args->{options} && exists $args->{options}{charServer}) {
- $charServer = $args->{options}{charServer};
- } else {
- $charServer = $net->serverPeerHost . ":" . $net->serverPeerPort;
- }
- my $blockSize = $self->received_characters_blockSize();
- for (my $i = $args->{RAW_MSG_SIZE} % $blockSize; $i < $args->{RAW_MSG_SIZE}; $i += $blockSize) {
- #exp display bugfix - chobit andy 20030129
- my $unpack_string = received_characters_unpackString();
- my ($cID,$exp,$zeny,$jobExp,$jobLevel, $opt1, $opt2, $option, $karma, $manner, $statpt,
- $hp,$maxHp,$sp,$maxSp, $walkspeed, $jobId,$hairstyle, $weapon, $level, $skillpt,$headLow, $shield,$headTop,$headMid,$hairColor,
- $clothesColor,$name,$str,$agi,$vit,$int,$dex,$luk,$slot, $rename, $map) =
- unpack($unpack_string, substr($args->{RAW_MSG}, $i));
- $chars[$slot] = new Actor::You;
- $chars[$slot]{ID} = $accountID;
- $chars[$slot]{charID} = $cID;
- $chars[$slot]{exp} = $exp;
- $chars[$slot]{zeny} = $zeny;
- $chars[$slot]{exp_job} = $jobExp;
- $chars[$slot]{lv_job} = $jobLevel;
- $chars[$slot]{hp} = $hp;
- $chars[$slot]{hp_max} = $maxHp;
- $chars[$slot]{sp} = $sp;
- $chars[$slot]{sp_max} = $maxSp;
- $chars[$slot]{jobID} = $jobId;
- $chars[$slot]{hair_style} = $hairstyle;
- $chars[$slot]{lv} = $level;
- $chars[$slot]{headgear}{low} = $headLow;
- $chars[$slot]{headgear}{top} = $headTop;
- $chars[$slot]{headgear}{mid} = $headMid;
- $chars[$slot]{hair_color} = $hairColor;
- $chars[$slot]{clothes_color} = $clothesColor;
- $chars[$slot]{name} = $name;
- $chars[$slot]{str} = $str;
- $chars[$slot]{agi} = $agi;
- $chars[$slot]{vit} = $vit;
- $chars[$slot]{int} = $int;
- $chars[$slot]{dex} = $dex;
- $chars[$slot]{luk} = $luk;
- $chars[$slot]{sex} = $accountSex2;
- $chars[$slot]{map} = $map;
- $chars[$slot]{nameID} = unpack("V", $chars[$slot]{ID});
- $chars[$slot]{name} = bytesToString($chars[$slot]{name});
- }
- # gradeA says it's supposed to send this packet here, but
- # it doesn't work...
- # 30 Dec 2005: it didn't work before because it wasn't sending the accountiD -> fixed (kaliwanagan)
- $messageSender->sendBanCheck($accountID) if (!$net->clientAlive && $config{serverType} == 2);
- if (charSelectScreen(1) == 1) {
- $firstLoginMap = 1;
- $startingzeny = $chars[$config{'char'}]{'zeny'} unless defined $startingzeny;
- $sentWelcomeMessage = 1;
- }
- }
- sub character_name {
- my ($self, $args) = @_;
- my $name; # Type: String
- $name = bytesToString($args->{name});
- debug "Character name received: $name\n";
- }
- sub actor_name_received {
- my ($self, $args) = @_;
- # FIXME: There is more to this packet than just party name and guild name.
- # This packet is received when you leave a guild
- # (with cryptic party and guild name fields, at least for now)
- my $player = $playersList->getByID($args->{ID});
- if (defined $player) {
- # Receive names of players who are in a guild.
- $player->setName(bytesToString($args->{name}));
- $player->{party}{name} = bytesToString($args->{partyName});
- $player->{guild}{name} = bytesToString($args->{guildName});
- $player->{guild}{title} = bytesToString($args->{guildTitle});
- updatePlayerNameCache($player);
- debug "Player Info: $player->{name} ($player->{binID})\n", "parseMsg_presence", 2;
- Plugins::callHook('charNameUpdate', {player => $player});
- } else {
- debug "Player Info for " . unpack("V", $args->{ID}) .
- " (not on screen): " . bytesToString($args->{name}) . "\n",
- "parseMsg_presence/remote", 2;
- }
- my $monster = $monstersList->getByID($args->{ID});
- if ($monster) {
- my $name = bytesToString($args->{name});
- debug "Monster Info 2: $name ($monster->{binID})\n", "parseMsg", 2;
- $monster->{name_given} = $name;
- if ($monsters_lut{$monster->{nameID}} eq "") {
- $monster->setName($name);
- $monsters_lut{$monster->{nameID}} = $name;
- updateMonsterLUT(Settings::getTableFilename("monsters.txt"), $monster->{nameID}, $name);
- }
- }
- }
- sub items_nonstackable {
- my ($self, $args) = @_;
- my $items = $self->{nested}->{items_nonstackable};
- if($args->{switch} eq '00A4' || # inventory
- $args->{switch} eq '00A6' || # storage
- $args->{switch} eq '0122' # cart
- ) {
- return $items->{type1};
- } elsif ($args->{switch} eq '0295' || # inventory
- $args->{switch} eq '0296' || # storage
- $args->{switch} eq '0297' # cart
- ) {
- return $items->{type2};
- } elsif ($args->{switch} eq '02D0' || # inventory
- $args->{switch} eq '02D1' || # storage
- $args->{switch} eq '02D2' # cart
- ) {
- return $items->{type3};
- } else {
- warning "items_nonstackable: unsupported packet ($args->{switch})!\n";
- }
- }
- sub changeToInGameState {
- if ($net->version() == 1) {
- if ($accountID && UNIVERSAL::isa($char, 'Actor::You')) {
- if ($net->getState() != Network::IN_GAME) {
- $net->setState(Network::IN_GAME);
- }
- return 1;
- } else {
- if ($net->getState() != Network::IN_GAME_BUT_UNINITIALIZED) {
- $net->setState(Network::IN_GAME_BUT_UNINITIALIZED);
- if ($config{verbose} && $messageSender && !$sentWelcomeMessage) {
- $messageSender->injectAdminMessage("Please relogin to enable X-${Settings::NAME}.");
- $sentWelcomeMessage = 1;
- }
- }
- return 0;
- }
- } else {
- return 1;
- }
- }
- sub actor_display {
- my ($self, $args) = @_;
- return unless changeToInGameState();
- my ($actor, $mustAdd);
- #### Initialize ####
- my $nameID = unpack("V", $args->{ID});
- if ($args->{switch} eq "0086") {
- # Message 0086 contains less information about the actor than other similar
- # messages. So we use the existing actor information.
- my $coordsArg = $args->{coords};
- my $tickArg = $args->{tick};
- $args = Actor::get($args->{ID})->deepCopy();
- # Here we overwrite the $args data with the 0086 packet data.
- $args->{switch} = "0086";
- $args->{coords} = $coordsArg;
- $args->{tick} = $tickArg; # lol tickcount what do we do with that? debug "tick: " . $tickArg/1000/3600/24 . "\n";
- }
- my (%coordsFrom, %coordsTo);
- if ($args->{switch} eq "007B" ||
- $args->{switch} eq "0086" ||
- $args->{switch} eq "01DA" ||
- $args->{switch} eq "022C" ||
- $args->{switch} eq "02EC" ||
- $args->{switch} eq "07F7" ||
- $args->{switch} eq "0856") {
- # Actor Moved
- makeCoordsFromTo(\%coordsFrom, \%coordsTo, $args->{coords}); # body dir will be calculated using the vector
- } else {
- # Actor Spawned/Exists
- makeCoordsDir(\%coordsTo, $args->{coords}, \$args->{body_dir});
- %coordsFrom = %coordsTo;
- }
- # Remove actors that are located outside the map
- # This may be caused by:
- # - server sending us false actors
- # - actor packets not being parsed correctly
- if (defined $field && ($field->isOffMap($coordsFrom{x}, $coordsFrom{y}) || $field->isOffMap($coordsTo{x}, $coordsTo{y}))) {
- 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());
- return;
- }
- # Remove actors with a distance greater than removeActorWithDistance. Useful for vending (so you don't spam
- # too many packets in prontera and cause server lag). As a side effect, you won't be able to "see" actors
- # beyond removeActorWithDistance.
- if ($config{removeActorWithDistance}) {
- if ((my $block_dist = blockDistance($char->{pos_to}, \%coordsTo)) > ($config{removeActorWithDistance})) {
- my $nameIdTmp = unpack("V", $args->{ID});
- debug "Removed out of sight actor $nameIdTmp at ($coordsTo{x}, $coordsTo{y}) (distance: $block_dist)\n";
- return;
- }
- }
- =pod
- # Zealotus bug
- if ($args->{type} == 1200) {
- open DUMP, ">> test_Zealotus.txt";
- print DUMP "Zealotus: " . $nameID . "\n";
- print DUMP Dumper($args);
- close DUMP;
- }
- =cut
- #### Step 1: create/get the correct actor object ####
- if ($jobs_lut{$args->{type}}) {
- unless ($args->{type} > 6000) {
- # Actor is a player
- $actor = $playersList->getByID($args->{ID});
- if (!defined $actor) {
- $actor = new Actor::Player();
- $actor->{appear_time} = time;
- $mustAdd = 1;
- }
- $actor->{nameID} = $nameID;
- } else {
- # Actor is a homunculus or a mercenary
- $actor = $slavesList->getByID($args->{ID});
- if (!defined $actor) {
- $actor = ($char->{slaves} && $char->{slaves}{$args->{ID}})
- ? $char->{slaves}{$args->{ID}} : new Actor::Slave ($args->{type});
- $actor->{appear_time} = time;
- $mustAdd = 1;
- }
- $actor->{nameID} = $nameID;
- }
- } elsif ($args->{type} == 45) {
- # Actor is a portal
- $actor = $portalsList->getByID($args->{ID});
- if (!defined $actor) {
- $actor = new Actor::Portal();
- $actor->{appear_time} = time;
- my $exists = portalExists($field->baseName, \%coordsTo);
- $actor->{source}{map} = $field->baseName;
- if ($exists ne "") {
- $actor->setName("$portals_lut{$exists}{source}{map} -> " . getPortalDestName($exists));
- }
- $mustAdd = 1;
- # Strangely enough, portals (like all other actors) have names, too.
- # We _could_ send a "actor_info_request" packet to find the names of each portal,
- # however I see no gain from this. (And it might even provide another way of private
- # servers to auto-ban bots.)
- }
- $actor->{nameID} = $nameID;
- } elsif ($args->{type} >= 1000) { # FIXME: in rare cases RO uses a monster sprite for NPC's (JT_ZHERLTHSH = 0x4b0 = 1200) ==> use object_type ?
- # Actor might be a monster
- if ($args->{hair_style} == 0x64) {
- # Actor is a pet
- $actor = $petsList->getByID($args->{ID});
- if (!defined $actor) {
- $actor = new Actor::Pet();
- $actor->{appear_time} = time;
- if ($monsters_lut{$args->{type}}) {
- $actor->setName($monsters_lut{$args->{type}});
- }
- $actor->{name_given} = "Unknown";
- $mustAdd = 1;
- # Previously identified monsters could suddenly be identified as pets.
- if ($monstersList->getByID($args->{ID})) {
- $monstersList->removeByID($args->{ID});
- }
- }
- } else {
- # Actor really is a monster
- $actor = $monstersList->getByID($args->{ID});
- if (!defined $actor) {
- $actor = new Actor::Monster();
- $actor->{appear_time} = time;
- if ($monsters_lut{$args->{type}}) {
- $actor->setName($monsters_lut{$args->{type}});
- }
- $actor->{name_given} = "Unknown";
- $actor->{binType} = $args->{type};
- $mustAdd = 1;
- }
- }
- # Why do monsters and pets use nameID as type?
- $actor->{nameID} = $args->{type};
- } else { # ($args->{type} < 1000 && $args->{type} != 45 && !$jobs_lut{$args->{type}})
- # Actor is an NPC
- $actor = $npcsList->getByID($args->{ID});
- if (!defined $actor) {
- $actor = new Actor::NPC();
- $actor->{appear_time} = time;
- $mustAdd = 1;
- }
- $actor->{nameID} = $nameID;
- }
- #### Step 2: update actor information ####
- $actor->{ID} = $args->{ID};
- $actor->{jobID} = $args->{type};
- $actor->{type} = $args->{type};
- $actor->{lv} = $args->{lv};
- $actor->{pos} = {%coordsFrom};
- $actor->{pos_to} = {%coordsTo};
- $actor->{walk_speed} = $args->{walk_speed} / 1000 if (exists $args->{walk_speed} && $args->{switch} ne "0086");
- $actor->{time_move} = time;
- $actor->{time_move_calc} = distance(\%coordsFrom, \%coordsTo) * $actor->{walk_speed};
- if (UNIVERSAL::isa($actor, "Actor::Player")) {
- # None of this stuff should matter if the actor isn't a player... => does matter for a guildflag npc!
- # Interesting note about emblemID. If it is 0 (or none), the Ragnarok
- # client will display "Send (Player) a guild invitation" (assuming one has
- # invitation priveledges), regardless of whether or not guildID is set.
- # I bet that this is yet another brilliant "feature" by GRAVITY's good programmers.
- $actor->{emblemID} = $args->{emblemID} if (exists $args->{emblemID});
- $actor->{guildID} = $args->{guildID} if (exists $args->{guildID});
- if (exists $args->{lowhead}) {
- $actor->{headgear}{low} = $args->{lowhead};
- $actor->{headgear}{mid} = $args->{midhead};
- $actor->{headgear}{top} = $args->{tophead};
- $actor->{weapon} = $args->{weapon};
- $actor->{shield} = $args->{shield};
- }
- $actor->{sex} = $args->{sex};
- if ($args->{act} == 1) {
- $actor->{dead} = 1;
- } elsif ($args->{act} == 2) {
- $actor->{sitting} = 1;
- }
- # Monsters don't have hair colors or heads to look around...
- $actor->{hair_color} = $args->{hair_color} if (exists $args->{hair_color});
- } elsif (UNIVERSAL::isa($actor, "Actor::NPC") && $args->{type} == 722) { # guild flag has emblem
- # odd fact: "this data can also be found in a strange place:
- # (shield OR lowhead) + midhead = emblemID (either shield or lowhead depending on the packet)
- # tophead = guildID
- $actor->{emblemID} = $args->{emblemID};
- $actor->{guildID} = $args->{guildID};
- }
- # But hair_style is used for pets, and their bodies can look different ways...
- $actor->{hair_style} = $args->{hair_style} if (exists $args->{hair_style});
- $actor->{look}{body} = $args->{body_dir} if (exists $args->{body_dir});
- $actor->{look}{head} = $args->{head_dir} if (exists $args->{head_dir});
- # When stance is non-zero, character is bobbing as if they had just got hit,
- # but the cursor also turns to a sword when they are mouse-overed.
- #$actor->{stance} = $args->{stance} if (exists $args->{stance});
- # Visual effects are a set of flags (some of the packets don't have this argument)
- $actor->{opt3} = $args->{opt3} if (exists $args->{opt3}); # stackable
- # Known visual effects:
- # 0x0001 = Yellow tint (eg, a quicken skill)
- # 0x0002 = Red tint (eg, power-thrust)
- # 0x0004 = Gray tint (eg, energy coat)
- # 0x0008 = Slow lightning (eg, mental strength)
- # 0x0010 = Fast lightning (eg, MVP fury)
- # 0x0020 = Black non-moving statue (eg, stone curse)
- # 0x0040 = Translucent weapon
- # 0x0080 = Translucent red sprite (eg, marionette control?)
- # 0x0100 = Spaztastic weapon image (eg, mystical amplification)
- # 0x0200 = Gigantic glowy sphere-thing
- # 0x0400 = Translucent pink sprite (eg, marionette control?)
- # 0x0800 = Glowy sprite outline (eg, assumptio)
- # 0x1000 = Bright red sprite, slowly moving red lightning (eg, MVP fury?)
- # 0x2000 = Vortex-type effect
- # Note that these are flags, and you can mix and match them
- # Example: 0x000C (0x0008 & 0x0004) = gray tint with slow lightning
- =pod
- typedef enum <unnamed-tag> {
- SHOW_EFST_NORMAL = 0x0,
- SHOW_EFST_QUICKEN = 0x1,
- SHOW_EFST_OVERTHRUST = 0x2,
- SHOW_EFST_ENERGYCOAT = 0x4,
- SHOW_EFST_EXPLOSIONSPIRITS = 0x8,
- SHOW_EFST_STEELBODY = 0x10,
- SHOW_EFST_BLADESTOP = 0x20,
- SHOW_EFST_AURABLADE = 0x40,
- SHOW_EFST_REDBODY = 0x80,
- SHOW_EFST_LIGHTBLADE = 0x100,
- SHOW_EFST_MOON = 0x200,
- SHOW_EFST_PINKBODY = 0x400,
- SHOW_EFST_ASSUMPTIO = 0x800,
- SHOW_EFST_SUN_WARM = 0x1000,
- SHOW_EFST_REFLECT = 0x2000,
- SHOW_EFST_BUNSIN = 0x4000,
- SHOW_EFST_SOULLINK = 0x8000,
- SHOW_EFST_UNDEAD = 0x10000,
- SHOW_EFST_CONTRACT = 0x20000,
- } <unnamed-tag>;
- =cut
- # Save these parameters ...
- $actor->{opt1} = $args->{opt1}; # nonstackable
- $actor->{opt2} = $args->{opt2}; # stackable
- $actor->{option} = $args->{option}; # stackable
- # And use them to set status flags.
- if (setStatus($actor, $args->{opt1}, $args->{opt2}, $args->{option})) {
- $mustAdd = 0;
- }
- #### Step 3: Add actor to actor list ####
- if ($mustAdd) {
- if (UNIVERSAL::isa($actor, "Actor::Player")) {
- $playersList->add($actor);
- } elsif (UNIVERSAL::isa($actor, "Actor::Monster")) {
- $monstersList->add($actor);
- } elsif (UNIVERSAL::isa($actor, "Actor::Pet")) {
- $petsList->add($actor);
- } elsif (UNIVERSAL::isa($actor, "Actor::Portal")) {
- $portalsList->add($actor);
- } elsif (UNIVERSAL::isa($actor, "Actor::NPC")) {
- my $ID = $args->{ID};
- my $location = $field->baseName . " $actor->{pos}{x} $actor->{pos}{y}";
- if ($npcs_lut{$location}) {
- $actor->setName($npcs_lut{$location});
- }
- $npcsList->add($actor);
- } elsif (UNIVERSAL::isa($actor, "Actor::Slave")) {
- $slavesList->add($actor);
- }
- }
- #### Packet specific ####
- if ($args->{switch} eq "0078" ||
- $args->{switch} eq "01D8" ||
- $args->{switch} eq "022A" ||
- $args->{switch} eq "02EE" ||
- $args->{switch} eq "07F9" ||
- $args->{switch} eq "0857") {
- # Actor Exists (standing)
- if ($actor->isa('Actor::Player')) {
- my $domain = existsInList($config{friendlyAID}, unpack("V", $actor->{ID})) ? 'parseMsg_presence' : 'parseMsg_presence/player';
- debug "Player Exists: " . $actor->name . " ($actor->{binID}) Level $actor->{lv} $sex_lut{$actor->{sex}} $jobs_lut{$actor->{jobID}} ($coordsFrom{x}, $coordsFrom{y})\n", $domain;
- Plugins::callHook('player', {player => $actor}); #backwards compatibility
- Plugins::callHook('player_exist', {player => $actor});
- } elsif ($actor->isa('Actor::NPC')) {
- 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;
- } elsif ($actor->isa('Actor::Portal')) {
- message TF("Portal Exists: %s (%s, %s) - (%s)\n", $actor->name, $actor->{pos_to}{x}, $actor->{pos_to}{y}, $actor->{binID}), "portals", 1;
- } elsif ($actor->isa('Actor::Monster')) {
- debug sprintf("Monster Exists: %s (%d)\n", $actor->name, $actor->{binID}), "parseMsg_presence", 1;
- } elsif ($actor->isa('Actor::Pet')) {
- debug sprintf("Pet Exists: %s (%d)\n", $actor->name, $actor->{binID}), "parseMsg_presence", 1;
- } elsif ($actor->isa('Actor::Slave')) {
- debug sprintf("Slave Exists: %s (%d)\n", $actor->name, $actor->{binID}), "parseMsg_presence", 1;
- } else {
- debug sprintf("Unknown Actor Exists: %s (%d)\n", $actor->name, $actor->{binID}), "parseMsg_presence", 1;
- }
- } elsif ($args->{switch} eq "0079" ||
- $args->{switch} eq "01DB" ||
- $args->{switch} eq "022B" ||
- $args->{switch} eq "02ED" ||
- $args->{switch} eq "01D9" ||
- $args->{switch} eq "07F8" ||
- $args->{switch} eq "0858") {
- # Actor Connected (new)
- if ($actor->isa('Actor::Player')) {
- my $domain = existsInList($config{friendlyAID}, unpack("V", $args->{ID})) ? 'parseMsg_presence' : 'parseMsg_presence/player';
- debug "Player Connected: ".$actor->name." ($actor->{binID}) Level $args->{lv} $sex_lut{$actor->{sex}} $jobs_lut{$actor->{jobID}} ($coordsTo{x}, $coordsTo{y})\n", $domain;
- Plugins::callHook('player', {player => $actor}); #backwards compatibailty
- Plugins::callHook('player_connected', {player => $actor});
- } else {
- debug "Unknown Connected: $args->{type} - ", "parseMsg";
- }
- } elsif ($args->{switch} eq "007B" ||
- $args->{switch} eq "0086" ||
- $args->{switch} eq "01DA" ||
- $args->{switch} eq "022C" ||
- $args->{switch} eq "02EC" ||
- $args->{switch} eq "07F7" ||
- $args->{switch} eq "0856") {
- # Actor Moved
- # Correct the direction in which they're looking
- my %vec;
- getVector(\%vec, \%coordsTo, \%coordsFrom);
- my $direction = int sprintf("%.0f", (360 - vectorToDegree(\%vec)) / 45);
- $actor->{look}{body} = $direction;
- $actor->{look}{head} = 0;
- if ($actor->isa('Actor::Player')) {
- 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";
- } elsif ($actor->isa('Actor::Monster')) {
- debug "Monster Moved: " . $actor->nameIdx . " - ($coordsFrom{x}, $coordsFrom{y}) -> ($coordsTo{x}, $coordsTo{y})\n", "parseMsg";
- } elsif ($actor->isa('Actor::Pet')) {
- debug "Pet Moved: " . $actor->nameIdx . " - ($coordsFrom{x}, $coordsFrom{y}) -> ($coordsTo{x}, $coordsTo{y})\n", "parseMsg";
- } elsif ($actor->isa('Actor::Slave')) {
- debug "Slave Moved: " . $actor->nameIdx . " - ($coordsFrom{x}, $coordsFrom{y}) -> ($coordsTo{x}, $coordsTo{y})\n", "parseMsg";
- } elsif ($actor->isa('Actor::Portal')) {
- # This can never happen of course.
- debug "Portal Moved: " . $actor->nameIdx . " - ($coordsFrom{x}, $coordsFrom{y}) -> ($coordsTo{x}, $coordsTo{y})\n", "parseMsg";
- } elsif ($actor->isa('Actor::NPC')) {
- # Neither can this.
- debug "NPC Moved: " . $actor->nameIdx . " - ($coordsFrom{x}, $coordsFrom{y}) -> ($coordsTo{x}, $coordsTo{y})\n", "parseMsg";
- } else {
- debug "Unknown Actor Moved: " . $actor->nameIdx . " - ($coordsFrom{x}, $coordsFrom{y}) -> ($coordsTo{x}, $coordsTo{y})\n", "parseMsg";
- }
- } elsif ($args->{switch} eq "007C") {
- # Actor Spawned
- if ($actor->isa('Actor::Player')) {
- debug "Player Spawned: " . $actor->nameIdx . " $sex_lut{$actor->{sex}} $jobs_lut{$actor->{jobID}}\n", "parseMsg";
- } elsif ($actor->isa('Actor::Monster')) {
- debug "Monster Spawned: " . $actor->nameIdx . "\n", "parseMsg";
- } elsif ($actor->isa('Actor::Pet')) {
- debug "Pet Spawned: " . $actor->nameIdx . "\n", "parseMsg";
- } elsif ($actor->isa('Actor::Slave')) {
- debug "Slave Spawned: " . $actor->nameIdx . " $jobs_lut{$actor->{jobID}}\n", "parseMsg";
- } elsif ($actor->isa('Actor::Portal')) {
- # Can this happen?
- debug "Portal Spawned: " . $actor->nameIdx . "\n", "parseMsg";
- } elsif ($actor->isa('NPC')) {
- debug "NPC Spawned: " . $actor->nameIdx . "\n", "parseMsg";
- } else {
- debug "Unknown Spawned: " . $actor->nameIdx . "\n", "parseMsg";
- }
- }
- }
- sub skill_post_delay {
- my ($self, $args) = @_;
- my $skillName = (new Skill(idn => $args->{ID}))->getName;
- my $status = defined $statusName{'EFST_DELAY'} ? $statusName{'EFST_DELAY'} : ' Delay';
- $char->setStatus($skillName.$status, 1, $args->{time});
- }
- =pod
- packet_ver: 26
- 0x0436,19,wanttoconnection,2:6:10:14:18
- 0x035f,5,walktoxy,2
- 0x0360,6,ticksend,2
- 0x0361,5,changedir,2:4
- 0x0362,6,takeitem,2
- 0x0363,6,dropitem,2:4
- 0x0364,8,movetokafra,2:4
- 0x0365,8,movefromkafra,2:4
- 0x0366,10,useskilltopos,2:4:6:8
- 0x0367,90,useskilltoposinfo,2:4:6:8:10
- 0x0368,6,getcharnamerequest,2
- 0x0369,6,solvecharname,2
- 0x0856,-1
- 0x0857,-1
- 0x0858,-1
- 0x0859,-1
- =cut
- 1;
Advertisement
Add Comment
Please, Sign In to add comment