From 04a428da2307cbce8a3909f2d320530e50d23ba2 Mon Sep 17 00:00:00 2001 From: Cydh Ramdh Date: Wed, 18 May 2016 20:32:04 +0700 Subject: [PATCH 1/5] Added 2 main features * Move Character Slot * Move slot option now will be shown on chracter select (+2 after char slot, after create new char option) * Known used packet: * char_move_slot (08D4): To send char move request. * char_move_slot_reply (08D5): Reply for char move. * Rename Character * Rename slot option now will be shown on chracter select (+3 after char slot, after move char slot option) * Known used packet: * char_rename (08FC): To send rename request. * char_renamed (08E3): Received a single charinfo for renamed char, only be sent by server if renaming is success. * char_rename_result (08FD): Reply of rename request. * Misc Edits * Delete option will be shown as +3 after char slot * Edited `received_characters_unpackString` unpack string notation to support 'Move Character Slot' and 'Rename Character' feature. * Added function 'sub received_characters_unpackString_Min' to unpack 'CharInfo' packet for renamed char. * PS: Only tested for idRO server, TODO maybe I'll do some tests for @rAthena Signed-off-by: Cydh Ramdh --- src/Misc.pm | 80 +++++++++++++- src/Network/Receive.pm | 169 ++++++++++++++++++++++++++++- src/Network/Receive/ServerType0.pm | 10 +- src/Network/Send.pm | 30 +++++ src/Network/Send/ServerType0.pm | 2 + 5 files changed, 284 insertions(+), 7 deletions(-) diff --git a/src/Misc.pm b/src/Misc.pm index 1de81da9ff..e728f5d8f7 100644 --- a/src/Misc.pm +++ b/src/Misc.pm @@ -1231,6 +1231,8 @@ sub charSelectScreen { } else { push @choices, T('Delete a character'); } + push @choices, T('Move a character slot'); + push @choices, T('Rename a character'); } else { message T("There are no characters on this account.\n"), "connection"; if ($config{char} ne "switch" && defined($char)) { @@ -1263,7 +1265,12 @@ sub charSelectScreen { } elsif ($choice == @charNames) { # 'Create character' chosen $mode = "create"; - + } elsif ($choice == @charNames+2) { + # 'Move a character slot' chosen + $mode = "move"; + } elsif ($choice == @charNames+3) { + # 'Rename a character' chosen + $mode = "rename"; } else { # 'Delete character' chosen $mode = "delete"; @@ -1372,6 +1379,77 @@ sub charSelectScreen { $AI::temp::delIndex = $charIndex; $timeout{charlogin}{time} = time; } + + } elsif ($mode eq "move") { + # TODO: + # 1. Character still can be moved to empty slot, so list the empty slot too. + # 2. Character move maybe fail when try to move to "Not Available" slots. + # 3. Character move maybe fail when try to move "Premium Service" or "Billing Service" slots. + my $choice = $interface->showMenu( + T("Select the character you want to move."), + \@charNames, + title => T("Move a character - Origin")); + if ($choice == -1) { + goto TOP; + } + my $charIndex = @charNameIndices[$choice]; + + if (!$chars[$charIndex]{moveCount}) { + message TF("Character %s cannot be moved.\n", $chars[$charIndex]{name}), "info"; + goto TOP; + } + my $choice2 = $interface->showMenu( + T("Select the destination slot."), + \@charNames, + title => T("Move a character - Destination")); + if ($choice2 == -1) { + goto TOP; + } + my $charToIndex = @charNameIndices[$choice2]; + + $messageSender->sendCharMoveSlot($charIndex, $charToIndex, $chars[$charIndex]{moveCount}); + message TF("Moving character %s from slot %d to %d...\n", $chars[$charIndex]{name}, $charIndex, $charToIndex), "connection"; + $AI::temp::moveIndex = $charIndex; + $AI::temp::moveToIndex = $charToIndex; + $timeout{charlogin}{time} = time; + + } elsif ($mode eq "rename") { + my $choice = $interface->showMenu( + T("Select the character you want to rename."), + \@charNames, + title => T("Rename a character")); + if ($choice == -1) { + goto TOP; + } + my $charIndex = @charNameIndices[$choice]; + + if (!$chars[$charIndex]{rename}) { + message TF("Character %s cannot be renamed.\n", $chars[$charIndex]{name}), "info"; + goto TOP; + } + + my $message = TF("Input new name for %s in format\n". + "\"(name)\"", $chars[$charIndex]{name}); + my $input = $interface->query($message); + unless ($input =~ /\S/) { + goto TOP; + } else { + my @args = parseArgs($input); + if (@args < 1) { + $interface->errorDialog(T("You didn't specify enough parameters."), 0); + goto TOP; + } + if (length $args[0] > 23) { + $interface->errorDialog(T("Name must not be longer than 23 characters."), 0); + goto TOP; + } + + $messageSender->sendCharRename($accountID, $chars[$charIndex]{charID}, $args[0]); + message TF("Renaming character \"%s\" to \"%s\"...\n", $chars[$charIndex]{name}, $args[0]), "connection"; + $AI::temp::charRenameIndex = $charIndex; + $AI::temp::charRenameName = $args[0]; + $timeout{charlogin}{time} = time; + } } return 2; } diff --git a/src/Network/Receive.pm b/src/Network/Receive.pm index 76867005fe..d65685748d 100644 --- a/src/Network/Receive.pm +++ b/src/Network/Receive.pm @@ -235,13 +235,14 @@ sub received_characters_unpackString { for ($masterServer && $masterServer->{charBlockSize}) { # unknown purpose (0 = disabled, otherwise displays "Add-Ons" sidebar) (from rA) # change $hairstyle - return 'a4 V9 v V2 v4 V v9 Z24 C8 v Z16 V x4 x4 x4 x1' if $_ == 147; - return 'a4 V9 v V2 v14 Z24 C8 v Z16 V x4 x4 x4 C' if $_ == 145; - return 'a4 V9 v V2 v14 Z24 C8 v Z16 V x4 x4 x4' if $_ == 144; + return 'a4 V9 v V2 v4 V v9 Z24 C8 v Z16 V4 C' if $_ == 147; + return 'a4 V9 v V2 v14 Z24 C8 v Z16 V4 C' if $_ == 145; + # rename char + return 'a4 V9 v V2 v14 Z24 C8 v Z16 V4' if $_ == 144; # change slot feature - return 'a4 V9 v V2 v14 Z24 C8 v Z16 V x4 x4' if $_ == 140; + return 'a4 V9 v V2 v14 Z24 C8 v Z16 V3' if $_ == 140; # robe - return 'a4 V9 v V2 v14 Z24 C8 v Z16 V x4' if $_ == 136; + return 'a4 V9 v V2 v14 Z24 C8 v Z16 V2' if $_ == 136; # delete date return 'a4 V9 v V2 v14 Z24 C8 v Z16 V' if $_ == 132; return 'a4 V9 v V2 v14 Z24 C8 v Z16' if $_ == 128; @@ -255,6 +256,32 @@ sub received_characters_unpackString { } } +# Just like received_characters_unpackString, just only from name block +sub received_characters_unpackString_Min { + for ($masterServer && $masterServer->{charBlockSize}) { + # unknown purpose (0 = disabled, otherwise displays "Add-Ons" sidebar) (from rA) + # change $hairstyle, last char is $charSex + return 'Z24 C8 v Z16 V4 C' if $_ == 147; + return 'Z24 C8 v Z16 V4 C' if $_ == 145; + # rename char + return 'Z24 C8 v Z16 V4' if $_ == 144; + # change slot feature + return 'Z24 C8 v Z16 V3' if $_ == 140; + # robe + return 'Z24 C8 v Z16 V2' if $_ == 136; + # delete date + return 'Z24 C8 v Z16 V' if $_ == 132; + return 'Z24 C8 v Z16' if $_ == 128; + # bRO (bitfrost update) + return 'Z24 C8 v Z12' if $_ == 124; + return 'Z24 C6 v2 x4' if $_ == 116; # TODO: (missing 2 last bytes) + return 'Z24 C6 v2' if $_ == 112; + return 'Z24 C6 v2' if $_ == 108; + return 'Z24 C6 v' if $_ == 106 || !$_; + die "Unknown charBlockSize: $_"; + } +} + ### Parse/reconstruct callbacks and packet handlers sub parse_account_server_info { @@ -4139,4 +4166,136 @@ sub deal_add_you { inventoryItemRemoved($item->{binID}, $currentDeal{lastItemAmount}); } +## +# 08D5 .W .W .W +# @author [Cydh] +## +sub char_move_slot_reply { + my ($self, $args) = @_; + if ($args->{reply} == 0) { + if (defined $AI::temp::moveIndex) { + message TF("Character %s moved from %d to %d.\n", $chars[$AI::temp::moveIndex]{name}, $AI::temp::moveIndex, $AI::temp::moveToIndex), "info"; + my $movedChar = $chars[$AI::temp::moveIndex]; # Save temp + $chars[$AI::temp::moveIndex] = $chars[$AI::temp::moveToIndex]; + $chars[$AI::temp::moveToIndex] = $movedChar; + $chars[$AI::temp::moveToIndex]{moveCount} = $args->{moveCount}; + undef $AI::temp::moveIndex; + undef $AI::temp::moveToIndex; + } else { + message T("Character moved.\n"), "info"; + relog(10); + return; + } + } else { + if (defined $AI::temp::moveIndex) { + message TF("Failed to move character %s from %d to %d.\n", $chars[$AI::temp::moveIndex]{name}, $AI::temp::moveIndex, $AI::temp::moveToIndex), "info"; + undef $AI::temp::moveIndex; + undef $AI::temp::moveToIndex; + } else { + message T("Failed to move a character slot.\n"), "info"; + } + } + + if (charSelectScreen() == 1) { + $net->setState(3); + $firstLoginMap = 1; + $startingzeny = $chars[$config{'char'}]{'zeny'} unless defined $startingzeny; + $sentWelcomeMessage = 1; + } + debug "char_move_slot_reply unknown:$args->{unknown}, reply:$args->{reply}, moveCount:$args->{moveCount}\n", "parseMsg"; +} + +## +# 08E3 .L .74B .66B +# CharInfo: 'Z24 C8 v Z16 V4' +# @author [Cydh] +## +sub char_renamed { + my ($self, $args) = @_; + + if (defined $AI::temp::charRenameIndex) { + my $charIndex = $AI::temp::charRenameIndex; + message TF("Character \"%s\" renamed to \"%s\"\n", $chars[$charIndex]{name}, $AI::temp::charRenameName), "info"; + my $unpack_string = $self->received_characters_unpackString_Min; + my ($name, $str, $agi, $vit, $int, $dex, $luk, $slot, $rename, $unknown, $mapname, $deleteDate, + $robe, $moveCount, $rename2,$charSex) = + unpack($unpack_string, $args->{charInfo}); + + if ($name ne $AI::temp::charRenameName) { + error TF("Name mismatch! %s <-> %s\n", $name, $AI::temp::charRenameName), "info"; + } + + $chars[$charIndex]{name} = $name; + $chars[$charIndex]{str} = $str; + $chars[$charIndex]{agi} = $agi; + $chars[$charIndex]{vit} = $vit; + $chars[$charIndex]{int} = $int; + $chars[$charIndex]{dex} = $dex; + $chars[$charIndex]{luk} = $luk; + setCharDeleteDate($charIndex, $deleteDate) if $deleteDate; + $chars[$charIndex]{name} = bytesToString($chars[$charIndex]{name}); + $chars[$charIndex]{robe} = $robe; + $chars[$charIndex]{moveCount} = $moveCount; + $chars[$charIndex]{rename} = $rename2; + $chars[$charIndex]{charSex} = $charSex; + + undef $AI::temp::charRenameIndex; + undef $AI::temp::charRenameName; + + if (charSelectScreen() == 1) { + $net->setState(3); + $firstLoginMap = 1; + $startingzeny = $chars[$config{'char'}]{'zeny'} unless defined $startingzeny; + $sentWelcomeMessage = 1; + } + } else { + message T("Character renamed.\n"), "info"; + relog(10); + return; + } + + debug "char_renamed result:$args->{result}\n", "parseMsg"; +} + +## +# 08FD .W .W +# @author [Cydh] +## +sub char_rename_result { + my ($self, $args) = @_; + + # 0: Success + if ($args->{result} == 0 && defined $AI::temp::charRenameIndex) { + my $charIndex = $AI::temp::charRenameIndex; + message TF("Character \"%s\" renamed to \"%s\"\n", $chars[$charIndex]{name}, $AI::temp::charRenameName), "info"; + return; + # 4: Fail already exists + } elsif ($args->{result} == 4) { + error TF("Cannot rename character to \"%s\". Name is already exists.\n", $AI::temp::charRenameName); + # 5: Fail in guild + } elsif ($args->{result} == 5) { + error TF("To rename a character you must withdraw from the guild.\n"); + # 5: Fail in party + } elsif ($args->{result} == 6) { + error TF("To rename a character you must withdraw from the party.\n"); + # 9: Invalid name + } elsif ($args->{result} == 9) { + error TF("Invalid new name \"%s\".\n", $AI::temp::charRenameName); + } else { + error TF("Unknown rename result occured:%d\n", $args->{result}); + } + + debug "char_rename_result result:$args->{result}\n", "parseMsg"; + + undef $AI::temp::charRenameIndex; + undef $AI::temp::charRenameName; + + if (charSelectScreen() == 1) { + $net->setState(3); + $firstLoginMap = 1; + $startingzeny = $chars[$config{'char'}]{'zeny'} unless defined $startingzeny; + $sentWelcomeMessage = 1; + } +} + 1; diff --git a/src/Network/Receive/ServerType0.pm b/src/Network/Receive/ServerType0.pm index 20b2ec2745..4041706a07 100644 --- a/src/Network/Receive/ServerType0.pm +++ b/src/Network/Receive/ServerType0.pm @@ -526,6 +526,9 @@ sub new { '08CB' => ['rates_info', 's4 a*', [qw(len exp death drop detail)]], '08CF' => ['revolving_entity', 'a4 v v', [qw(sourceID type entity)]], '08D2' => ['high_jump', 'a4 v2', [qw(ID x y)]], + '08D5' => ['char_move_slot_reply', 'v3', [qw(unknown reply moveCount)]], + '08E3' => ['char_renamed', 'a4 x74 a*', [qw(charID charInfo)]], + '08FD' => ['char_rename_result', 'v x', [qw(result)]], '08FF' => ['actor_status_active', 'a4 v V4', [qw(ID type tick unknown1 unknown2 unknown3)]], '0900' => ['inventory_items_stackable', 'v a*', [qw(len itemInfo)]], '0901' => ['inventory_items_nonstackable', 'v a*', [qw(len itemInfo)]], @@ -2845,7 +2848,8 @@ sub received_characters { # TODO: What would be the $unknown ? my ($cID,$exp,$zeny,$jobExp,$jobLevel, $opt1, $opt2, $option, $stance, $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, $unknown, $mapname, $deleteDate) = + $clothesColor,$name,$str,$agi,$vit,$int,$dex,$luk,$slot, $rename, $unknown, $mapname, $deleteDate, + $robe, $moveCount, $rename2, $charSex) = unpack($unpack_string, substr($args->{RAW_MSG}, $i)); $chars[$slot] = new Actor::You; @@ -2887,6 +2891,10 @@ sub received_characters { $chars[$slot]{name} = bytesToString($chars[$slot]{name}); $chars[$slot]{map_name} = $mapname; $chars[$slot]{map_name} =~ s/\.gat//g; + $chars[$slot]{robe} = $robe; + $chars[$slot]{moveCount} = $moveCount; + $chars[$slot]{rename} = $rename2; + $chars[$slot]{charSex} = $charSex; } # FIXME better support for multiple received_characters packets diff --git a/src/Network/Send.pm b/src/Network/Send.pm index c2f3f17fa2..5add47dcca 100644 --- a/src/Network/Send.pm +++ b/src/Network/Send.pm @@ -1156,4 +1156,34 @@ sub sendDealAddItem { debug sprintf("Sent Deal Add Item: %s, $amount\n", unpack('v', $ID)), "sendPacket", 2; } +## +# Move character slot +# 08D4 .W .W .W +# @author [Cydh] +## +sub sendCharMoveSlot { + my ($self, $from, $to, $count) = @_; + $self->sendToServer($self->reconstruct({switch => 'char_move_slot', fromSlot => $from, toSlot => $to, movesCount => $count})); +} + +sub reconstruct_char_move_slot { + my ($self, $args) = @_; + debug "Move character slot from $args->{from} to $args->{to}. Move chance $args->{movesCount}\n", "sendPacket"; +} + +## +# Request to rename char +# 08FC .L .24B +# @author [Cydh] +## +sub sendCharRename { + my ($self, $accID, $charID, $newName) = @_; + $self->sendToServer($self->reconstruct({switch => 'char_rename', accountID => $accID, charID => $charID, newName => $newName})); +} + +sub reconstruct_char_rename { + my ($self, $args) = @_; + debug "Request rename character ".hex($args->{charID})." (".hex($args->{accountID}).") to $args->{newName}\n", "sendPacket"; +} + 1; diff --git a/src/Network/Send/ServerType0.pm b/src/Network/Send/ServerType0.pm index 2f29ba4e65..d63aedfbb0 100644 --- a/src/Network/Send/ServerType0.pm +++ b/src/Network/Send/ServerType0.pm @@ -140,6 +140,8 @@ sub new { '08B8' => ['send_pin_password','a4 Z*', [qw(accountID pin)]], '08BA' => ['new_pin_password','a4 Z*', [qw(accountID pin)]], '08C9' => ['request_cashitems'],#2 + '08D4' => ['char_move_slot','v3', [qw(fromSlot toSlot movesCount)]], + '08FC' => ['char_rename', 'a4 a24', [qw(charID newName)]], '0987' => ['master_login', 'V Z24 a32 C', [qw(version username password_md5_hex master_version)]], '0998' => ['send_equip', 'a2 V', [qw(ID type)]],#8 '09A1' => ['sync_received_characters'], From c9301db4fce4d811a0b62d6d233ef726e67bdc97 Mon Sep 17 00:00:00 2001 From: Cydh Ramdh Date: Fri, 20 May 2016 05:55:42 +0700 Subject: [PATCH 2/5] Updated tables/packetdescriptions.txt Signed-off-by: Cydh Ramdh --- tables/packetdescriptions.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tables/packetdescriptions.txt b/tables/packetdescriptions.txt index 1eb08fbc57..5d7b498ec5 100644 --- a/tables/packetdescriptions.txt +++ b/tables/packetdescriptions.txt @@ -226,6 +226,9 @@ 0238 PK Top 10 Ranking 02AE Initialize Message ID Encryption 0A3B Hat Effect Info +08D5 Char Move Slot Reply +08E3 Char Renamed +08FD Char Rename Result [Send] 0064 Account Server Login @@ -338,3 +341,5 @@ 0829 Char Delete Accept 098F Char Delete Accept 082B Char Delete Cancel +08D4 Char Move Slot +08FC Char Rename From dae2e7474808a871651eea74303ea28aa138b7d8 Mon Sep 17 00:00:00 2001 From: Cydh Ramdh Date: Wed, 19 Dec 2018 17:59:36 +0700 Subject: [PATCH 3/5] attempt#1 --- src/Misc.pm | 10 +++------- src/Network/Receive.pm | 16 +++++++++------- src/Network/Receive/kRO/Sakexe_0.pm | 3 +++ src/Network/Send.pm | 14 ++++++++++++-- src/Network/Send/kRO/Sakexe_0.pm | 2 ++ 5 files changed, 29 insertions(+), 16 deletions(-) diff --git a/src/Misc.pm b/src/Misc.pm index be399d10f2..8e883c5aec 100644 --- a/src/Misc.pm +++ b/src/Misc.pm @@ -1447,10 +1447,6 @@ sub charSelectScreen { } } elsif ($mode eq "move") { - # TODO: - # 1. Character still can be moved to empty slot, so list the empty slot too. - # 2. Character move maybe fail when try to move to "Not Available" slots. - # 3. Character move maybe fail when try to move "Premium Service" or "Billing Service" slots. my $choice = $interface->showMenu( T("Select the character you want to move."), \@charNames, @@ -1460,7 +1456,7 @@ sub charSelectScreen { } my $charIndex = @charNameIndices[$choice]; - if (!$chars[$charIndex]{moveCount}) { + if (!$chars[$charIndex]{slot_addon}) { message TF("Character %s cannot be moved.\n", $chars[$charIndex]{name}), "info"; goto TOP; } @@ -1473,7 +1469,7 @@ sub charSelectScreen { } my $charToIndex = @charNameIndices[$choice2]; - $messageSender->sendCharMoveSlot($charIndex, $charToIndex, $chars[$charIndex]{moveCount}); + $messageSender->sendCharMoveSlot($charIndex, $charToIndex, $chars[$charIndex]{slot_addon}); message TF("Moving character %s from slot %d to %d...\n", $chars[$charIndex]{name}, $charIndex, $charToIndex), "connection"; $AI::temp::moveIndex = $charIndex; $AI::temp::moveToIndex = $charToIndex; @@ -1489,7 +1485,7 @@ sub charSelectScreen { } my $charIndex = @charNameIndices[$choice]; - if (!$chars[$charIndex]{rename}) { + if (!$chars[$charIndex]{rename_addon}) { message TF("Character %s cannot be renamed.\n", $chars[$charIndex]{name}), "info"; goto TOP; } diff --git a/src/Network/Receive.pm b/src/Network/Receive.pm index a8c60040d7..f8aabc98c6 100644 --- a/src/Network/Receive.pm +++ b/src/Network/Receive.pm @@ -738,7 +738,7 @@ sub received_characters { $character->{exp_job} = join '', reverse split / /, $character->{exp_job}; $character->{exp_job} = hex $character->{exp_job}; } - $character->{addon_rename} = $character->{addon_rename}; + debug "AID:$accountID CID:$char->{charID} rename:$character->{addon_rename} move:$character->{slot_addon}\n"; if ((!exists($character->{sex})) || ($character->{sex} ne "0" && $character->{sex} ne "1")) { $character->{sex} = $accountSex2; } @@ -819,6 +819,8 @@ sub character_creation_successful { $character->{exp} = 0; $character->{exp_job} = 0; + $character->{rename_addon} = 0; + $character->{slot_addon} = 0; if (!exists($character->{sex})) { $character->{sex} = $accountSex2; } @@ -7323,7 +7325,7 @@ sub char_move_slot_reply { my $movedChar = $chars[$AI::temp::moveIndex]; # Save temp $chars[$AI::temp::moveIndex] = $chars[$AI::temp::moveToIndex]; $chars[$AI::temp::moveToIndex] = $movedChar; - $chars[$AI::temp::moveToIndex]{moveCount} = $args->{moveCount}; + $chars[$AI::temp::moveToIndex]{slot_addon} = $args->{slot_addon}; undef $AI::temp::moveIndex; undef $AI::temp::moveToIndex; } else { @@ -7347,7 +7349,7 @@ sub char_move_slot_reply { $startingzeny = $chars[$config{'char'}]{'zeny'} unless defined $startingzeny; $sentWelcomeMessage = 1; } - debug "char_move_slot_reply unknown:$args->{unknown}, reply:$args->{reply}, moveCount:$args->{moveCount}\n", "parseMsg"; + debug "char_move_slot_reply unknown:$args->{unknown}, reply:$args->{reply}, slot_addon:$args->{slot_addon}\n", "parseMsg"; } ## @@ -7363,7 +7365,7 @@ sub char_renamed { message TF("Character \"%s\" renamed to \"%s\"\n", $chars[$charIndex]{name}, $AI::temp::charRenameName), "info"; my $unpack_string = $self->received_characters_unpackString_Min; my ($name, $str, $agi, $vit, $int, $dex, $luk, $slot, $rename, $unknown, $mapname, $deleteDate, - $robe, $moveCount, $rename2,$charSex) = + $robe, $slot_addon, $rename2,$charSex) = unpack($unpack_string, $args->{charInfo}); if ($name ne $AI::temp::charRenameName) { @@ -7380,8 +7382,8 @@ sub char_renamed { setCharDeleteDate($charIndex, $deleteDate) if $deleteDate; $chars[$charIndex]{name} = bytesToString($chars[$charIndex]{name}); $chars[$charIndex]{robe} = $robe; - $chars[$charIndex]{moveCount} = $moveCount; - $chars[$charIndex]{rename} = $rename2; + $chars[$charIndex]{slot_addon} = $slot_addon; + $chars[$charIndex]{rename_addon} = $rename2; $chars[$charIndex]{charSex} = $charSex; undef $AI::temp::charRenameIndex; @@ -7430,7 +7432,7 @@ sub char_rename_result { error TF("Unknown rename result occured:%d\n", $args->{result}); } - debug "char_rename_result result:$args->{result}\n", "parseMsg"; + debug "char_rename_result result:$args->{result}\n"; undef $AI::temp::charRenameIndex; undef $AI::temp::charRenameName; diff --git a/src/Network/Receive/kRO/Sakexe_0.pm b/src/Network/Receive/kRO/Sakexe_0.pm index 5bbe56d4c4..fdd8734bc3 100644 --- a/src/Network/Receive/kRO/Sakexe_0.pm +++ b/src/Network/Receive/kRO/Sakexe_0.pm @@ -535,6 +535,9 @@ sub new { '08D2' => ['high_jump', 'a4 v2', [qw(ID x y)]], # 10 '08B9' => ['login_pin_code_request', 'V a4 v', [qw(seed accountID flag)]], '08C8' => ['actor_action', 'a4 a4 a4 V3 x v C V', [qw(sourceID targetID tick src_speed dst_speed damage div type dual_wield_damage)]], + '08D5' => ['char_move_slot_reply', 'v3', [qw(unknown reply moveCount)]], + '08E3' => ['char_renamed', 'a4 x74 a*', [qw(charID charInfo)]], + '08FD' => ['char_rename_result', 'v x', [qw(result)]], '0906' => ['show_eq', 'v Z24 x17 a*', [qw(len name equips_info)]], '0908' => ['inventory_item_favorite', 'a2 C', [qw(ID flag)]],#5 '090F' => ['actor_connected', 'v C a4 v3 V v11 a4 a2 v V C2 a3 C2 v2 a9 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 opt4 name)]], diff --git a/src/Network/Send.pm b/src/Network/Send.pm index 4fe3461cb2..8acfff66b9 100644 --- a/src/Network/Send.pm +++ b/src/Network/Send.pm @@ -3072,7 +3072,12 @@ sub sendCashShopBuy { ## sub sendCharMoveSlot { my ($self, $from, $to, $count) = @_; - $self->sendToServer($self->reconstruct({switch => 'char_move_slot', fromSlot => $from, toSlot => $to, movesCount => $count})); + $self->sendToServer($self->reconstruct({ + switch => 'char_move_slot', + fromSlot => $from, + toSlot => $to, + movesCount => $count + })); } sub reconstruct_char_move_slot { @@ -3087,7 +3092,12 @@ sub reconstruct_char_move_slot { ## sub sendCharRename { my ($self, $accID, $charID, $newName) = @_; - $self->sendToServer($self->reconstruct({switch => 'char_rename', accountID => $accID, charID => $charID, newName => $newName})); + $self->sendToServer($self->reconstruct({ + switch => 'char_rename', + accountID => $accID, + charID => $charID, + newName => $newName + })); } sub reconstruct_char_rename { diff --git a/src/Network/Send/kRO/Sakexe_0.pm b/src/Network/Send/kRO/Sakexe_0.pm index e8e61811cd..d118aec19f 100644 --- a/src/Network/Send/kRO/Sakexe_0.pm +++ b/src/Network/Send/kRO/Sakexe_0.pm @@ -220,6 +220,8 @@ sub new { '08B8' => ['send_pin_password','a4 Z*', [qw(accountID pin)]], '08C1' => ['macro_start'],#2 '08C2' => ['macro_stop'],#2 + '08D4' => ['char_move_slot','v3', [qw(fromSlot toSlot movesCount)]], + '08FC' => ['char_rename', 'a4 a24', [qw(charID newName)]], '097C' => ['rank_general', 'v', [qw(type)]], '098D' => ['clan_chat', 'v Z*', [qw(len message)]], '09E9' => ['rodex_close_mailbox'], # 2 -- RodexCloseMailbox From 704e8dc9f2b430d65cf32819f1b8dc07e707e1fc Mon Sep 17 00:00:00 2001 From: Cydh Ramdh Date: Wed, 19 Dec 2018 19:06:43 +0700 Subject: [PATCH 4/5] Rename feature updates * Correction * Tested in idRO (~8x times LOL) --- src/Misc.pm | 4 ++-- src/Network/Receive.pm | 23 ++++++----------------- src/Network/Receive/ServerType0.pm | 2 +- src/Network/Receive/kRO/Sakexe_0.pm | 2 +- src/Network/Send.pm | 2 +- 5 files changed, 11 insertions(+), 22 deletions(-) diff --git a/src/Misc.pm b/src/Misc.pm index 8e883c5aec..217a7f3304 100644 --- a/src/Misc.pm +++ b/src/Misc.pm @@ -1331,6 +1331,7 @@ sub charSelectScreen { } elsif ($choice == @charNames) { # 'Create character' chosen $mode = "create"; + } elsif ($choice == @charNames+2) { # 'Move a character slot' chosen $mode = "move"; @@ -1490,8 +1491,7 @@ sub charSelectScreen { goto TOP; } - my $message = TF("Input new name for %s in format\n". - "\"(name)\"", $chars[$charIndex]{name}); + my $message = TF("Input new name for \"%s\" (4-23 characters)\n", $chars[$charIndex]{name}); my $input = $interface->query($message); unless ($input =~ /\S/) { goto TOP; diff --git a/src/Network/Receive.pm b/src/Network/Receive.pm index f8aabc98c6..d16707e482 100644 --- a/src/Network/Receive.pm +++ b/src/Network/Receive.pm @@ -738,7 +738,7 @@ sub received_characters { $character->{exp_job} = join '', reverse split / /, $character->{exp_job}; $character->{exp_job} = hex $character->{exp_job}; } - debug "AID:$accountID CID:$char->{charID} rename:$character->{addon_rename} move:$character->{slot_addon}\n"; + debug "rename:$character->{rename_addon} move:$character->{slot_addon}\n"; if ((!exists($character->{sex})) || ($character->{sex} ne "0" && $character->{sex} ne "1")) { $character->{sex} = $accountSex2; } @@ -7363,28 +7363,17 @@ sub char_renamed { if (defined $AI::temp::charRenameIndex) { my $charIndex = $AI::temp::charRenameIndex; message TF("Character \"%s\" renamed to \"%s\"\n", $chars[$charIndex]{name}, $AI::temp::charRenameName), "info"; - my $unpack_string = $self->received_characters_unpackString_Min; - my ($name, $str, $agi, $vit, $int, $dex, $luk, $slot, $rename, $unknown, $mapname, $deleteDate, - $robe, $slot_addon, $rename2,$charSex) = - unpack($unpack_string, $args->{charInfo}); + my $char_info = $self->received_characters_unpackString; + my $character = new Actor::You; + @{$character}{@{$char_info->{keys}}} = unpack($char_info->{types}, substr($args->{charInfo}, 0, $masterServer->{charBlockSize})); + my $name = bytesToString($character->{name}); if ($name ne $AI::temp::charRenameName) { error TF("Name mismatch! %s <-> %s\n", $name, $AI::temp::charRenameName), "info"; } $chars[$charIndex]{name} = $name; - $chars[$charIndex]{str} = $str; - $chars[$charIndex]{agi} = $agi; - $chars[$charIndex]{vit} = $vit; - $chars[$charIndex]{int} = $int; - $chars[$charIndex]{dex} = $dex; - $chars[$charIndex]{luk} = $luk; - setCharDeleteDate($charIndex, $deleteDate) if $deleteDate; - $chars[$charIndex]{name} = bytesToString($chars[$charIndex]{name}); - $chars[$charIndex]{robe} = $robe; - $chars[$charIndex]{slot_addon} = $slot_addon; - $chars[$charIndex]{rename_addon} = $rename2; - $chars[$charIndex]{charSex} = $charSex; + $chars[$charIndex]{rename_addon} = $character->{rename_addon}; undef $AI::temp::charRenameIndex; undef $AI::temp::charRenameName; diff --git a/src/Network/Receive/ServerType0.pm b/src/Network/Receive/ServerType0.pm index 86962a54de..632e521864 100644 --- a/src/Network/Receive/ServerType0.pm +++ b/src/Network/Receive/ServerType0.pm @@ -536,7 +536,7 @@ sub new { '08CF' => ['revolving_entity', 'a4 v v', [qw(sourceID type entity)]], '08D2' => ['high_jump', 'a4 v2', [qw(ID x y)]], '08D5' => ['char_move_slot_reply', 'v3', [qw(unknown reply moveCount)]], - '08E3' => ['char_renamed', 'a4 x74 a*', [qw(charID charInfo)]], + '08E3' => ['char_renamed', 'a*', [qw(charInfo)]], '08FD' => ['char_rename_result', 'v x', [qw(result)]], '08FF' => ['actor_status_active', 'a4 v V4', [qw(ID type tick unknown1 unknown2 unknown3)]], '0900' => ['inventory_items_stackable', 'v a*', [qw(len itemInfo)]], diff --git a/src/Network/Receive/kRO/Sakexe_0.pm b/src/Network/Receive/kRO/Sakexe_0.pm index fdd8734bc3..2a61d6c7f4 100644 --- a/src/Network/Receive/kRO/Sakexe_0.pm +++ b/src/Network/Receive/kRO/Sakexe_0.pm @@ -536,7 +536,7 @@ sub new { '08B9' => ['login_pin_code_request', 'V a4 v', [qw(seed accountID flag)]], '08C8' => ['actor_action', 'a4 a4 a4 V3 x v C V', [qw(sourceID targetID tick src_speed dst_speed damage div type dual_wield_damage)]], '08D5' => ['char_move_slot_reply', 'v3', [qw(unknown reply moveCount)]], - '08E3' => ['char_renamed', 'a4 x74 a*', [qw(charID charInfo)]], + '08E3' => ['char_renamed', 'a*', [qw(charInfo)]], '08FD' => ['char_rename_result', 'v x', [qw(result)]], '0906' => ['show_eq', 'v Z24 x17 a*', [qw(len name equips_info)]], '0908' => ['inventory_item_favorite', 'a2 C', [qw(ID flag)]],#5 diff --git a/src/Network/Send.pm b/src/Network/Send.pm index 8acfff66b9..b1e2b86d3f 100644 --- a/src/Network/Send.pm +++ b/src/Network/Send.pm @@ -3102,7 +3102,7 @@ sub sendCharRename { sub reconstruct_char_rename { my ($self, $args) = @_; - debug "Request rename character ".hex($args->{charID})." (".hex($args->{accountID}).") to $args->{newName}\n", "sendPacket"; + debug "Renaming character to $args->{newName} CID:".unpack("V",$args->{charID})."/AID:".unpack("V",$args->{accountID})."\n", "sendPacket"; } 1; From 5561b87fdb67652da6fb54b2ba1882688e698741 Mon Sep 17 00:00:00 2001 From: Cydh Ramdh Date: Wed, 19 Dec 2018 19:58:53 +0700 Subject: [PATCH 5/5] Char move updates * removed lefctover * Fixed and tested with idRO Renewal --- src/Misc.pm | 23 +++++++++++++++++++---- src/Network/Receive.pm | 1 - 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/Misc.pm b/src/Misc.pm index 217a7f3304..e1382a13d4 100644 --- a/src/Misc.pm +++ b/src/Misc.pm @@ -1194,6 +1194,7 @@ sub charSelectScreen { # An array which maps an index in @charNames to an index in @chars my @charNameIndices; my $mode; + my $charSlots; # Check system version to delete a character my $charDeleteVersion; @@ -1250,8 +1251,8 @@ sub charSelectScreen { $messageMapName = sprintf(", %s", $chars[$num]{last_map}); } } - - push @charNames, TF("Slot %d: %s (%s, %s, level %d/%d%s)%s", + + my $char_str = TF("Slot %d: %s (%s, %s, level %d/%d%s)%s", $num, $chars[$num]{name}, $jobs_lut{$chars[$num]{'jobID'}}, @@ -1260,7 +1261,9 @@ sub charSelectScreen { $chars[$num]{lv_job}, $messageMapName, $messageDeleteDate); + push @charNames, $char_str; push @charNameIndices, $num; + $charSlots->{$num} = $char_str; } if (@charNames) { @@ -1461,14 +1464,26 @@ sub charSelectScreen { message TF("Character %s cannot be moved.\n", $chars[$charIndex]{name}), "info"; goto TOP; } + my @available_slots; + #TODO: + # 1. Check for premium service slots + # 2. Overslots. Example char slots are 40 in screen and producible only 6 but players have 27 chars! + # 3. Billing slots, idk how it works + for (my $i = 0; $i < ($charSvrSet{total_slot} > 0 ? $charSvrSet{total_slot} : $charSvrSet{producible_slot}); $i++) { + if ($charSlots->{$i} ne "") { + push @available_slots,$charSlots->{$i}; + } else { + push @available_slots, TF("Slot %d: Empty", $i); + } + } my $choice2 = $interface->showMenu( T("Select the destination slot."), - \@charNames, + \@available_slots, title => T("Move a character - Destination")); if ($choice2 == -1) { goto TOP; } - my $charToIndex = @charNameIndices[$choice2]; + my $charToIndex = (defined @charNameIndices[$choice2] ? @charNameIndices[$choice2] : $choice2); $messageSender->sendCharMoveSlot($charIndex, $charToIndex, $chars[$charIndex]{slot_addon}); message TF("Moving character %s from slot %d to %d...\n", $chars[$charIndex]{name}, $charIndex, $charToIndex), "connection"; diff --git a/src/Network/Receive.pm b/src/Network/Receive.pm index d16707e482..9607018ec5 100644 --- a/src/Network/Receive.pm +++ b/src/Network/Receive.pm @@ -738,7 +738,6 @@ sub received_characters { $character->{exp_job} = join '', reverse split / /, $character->{exp_job}; $character->{exp_job} = hex $character->{exp_job}; } - debug "rename:$character->{rename_addon} move:$character->{slot_addon}\n"; if ((!exists($character->{sex})) || ($character->{sex} ne "0" && $character->{sex} ne "1")) { $character->{sex} = $accountSex2; }