pRO's Update! Login Pincode..(similar to bRO)

Philippines

Moderators: waferbaron, Moderators

Forum rules
This server is currently not maintained and tables folder (including connection info) is outdated. Read the wiki for instructions on how to update those information. Please contribute your updated info. Contact Cozzie to join the team as a regular server supporter.
jkcorp
Noob
Noob
Posts: 4
Joined: 14 Aug 2014, 02:42
Noob?: No

Re: pRO's Update! Login Pincode..(similar to bRO)

#191 Post by jkcorp »

Hi brokenbokeh,

with the codes u provided for the src/Poseidon/RagnarokServer
should we replace the codes already on it or just add it on the bottom part
Replace all codes
error: BEGIN failed--compilation aborted at src/Poseidon/poseidon.pl

Added on bottom where original codes are
working pretty fine, once logon on poseidon server
chosen any of the novices = failed to connect
brokenbokeh
Plain Yogurt
Plain Yogurt
Posts: 50
Joined: 08 Aug 2014, 03:02
Noob?: No

Re: pRO's Update! Login Pincode..(similar to bRO)

#192 Post by brokenbokeh »

zonda wrote:ok. so i should use my real uname and pass? or anything should still work?
Anything should work and any 4 number pinCode.

Just use this. This is the whole RagnarokServer.pm

Code: Select all

###########################################################
# Poseidon server - Ragnarok Online server emulator
#
# This program is free software; you can redistribute it and/or 
# modify it under the terms of the GNU General Public License 
# as published by the Free Software Foundation; either version 2 
# of the License, or (at your option) any later version.
#
# Copyright (c) 2005-2006 OpenKore Development Team
###########################################################
# This class emulates a Ragnarok Online server.
# The RO client connects to this server. This server
# periodically sends a GameGuard query to the RO client,
# and saves the RO client's response.
###########################################################

# TODO:
# 1) make use of unpack strings to pack our packets depending on serverType
# 2) make plugin like connection algorithms for each serverType or 1 main algo on which serverTypes have hooks

package Poseidon::RagnarokServer;

use strict;
use Base::Server;
use base qw(Base::Server);
use Misc;
use Utils qw(binSize getCoordString timeOut getHex getTickCount);
use Poseidon::Config;
use FileParsers;
use Math::BigInt;

my %clientdata;

# Decryption Keys
my $enc_val1 = 0;
my $enc_val2 = 0;
my $enc_val3 = 0;
my $state    = 0;

sub new {
	my ($class, @args) = @_;
	my $self = $class->SUPER::new(@args);

	# int challengeNum
	#
	# The number of times that the RO client has sent a
	# GameGuard challenge packet.
	#
	# Invariant: challengeNum >= 0
	$self->{challengeNum} = 0;

	# Bytes response
	#
	# A response for the last GameGuard query.
	$self->{response} = undef;

	# Invariant: state ne ''
	$self->{state} = 'ready';
	
	# added servertypes support
	if (-e 'servertypes.txt') {
		parseSectionedFile('servertypes.txt', \%{$self->{type}});
	} else {
		parseSectionedFile('src/Poseidon/servertypes.txt', \%{$self->{type}});
	}
	
	if (!$self->{type}->{$config{server_type}}) {
		die "Invalid serverType specified. Please check your poseidon config file.\n";
	} else {
		print "Building RagnarokServer with serverType $config{server_type}...\n";
	}

	return $self;
}

##
# $RagnarokServer->query(Bytes packet)
# packet: The raw GameGuard query packet.
# Require: defined($packet) && $self->getState() eq 'ready'
# Ensure: $self->getState() eq 'requesting'
#
# Send a GameGuard query to the RO client.
sub query 
{
	my ($self, $packet) = @_;
	my $clients = $self->clients();

	for (my $i = 0; $i < @{$clients}; $i++) {
		if ($clients->[$i]) {
			if ($clients->[$i]{connectedToMap}) {
                		$clients->[$i]->send($packet);
                		$self->{state} = 'requesting';
                		return;
			}
		}
	}
	
	print "[RagnarokServer]-> Error: no Ragnarok Online client connected.\n";
}

##
# String $RagnarokServer->getState()
#
# Get the state of this RagnarokServer object.
# The result can be one of:
# 'ready' - The RO client is ready to handle another GameGuard query.
# 'requesting' - The query has been sent to the RO client, but it hasn't responded yet.
# 'requested' - The RO client has responded to the last GameGuard query.
# 'not connected' - The RO client hasn't connected to this server yet.
sub getState {
	my ($self) = @_;
	my $clients = $self->clients();

	if ($self->{state} eq 'requested') {
		return 'requested';
	} elsif (binSize($clients) == 0) {
		return 'not connected';
	} else {
		return $self->{state};
	}
}

##
# Bytes $RagnarokServer->readResponse()
# Require: $self->getState() eq 'requested'
# Ensure: defined(result) && $self->getState() eq 'ready'
#
# Read the response for the last GameGuard query.
sub readResponse {
	my $resp = $_[0]->{response};
	$_[0]->{response} = undef;
	$_[0]->{state} = 'ready';
	return $resp;
}


#####################################################

sub onClientNew 
{
	my ($self, $client, $index) = @_;

	if ( $state == 0 )
	{
		# Initialize Decryption
		$enc_val1 = 0;
		$enc_val2 = 0;
		$enc_val3 = 0;
	} else { $state = 0; }
	
	$self->{challengeNum} = 0;
	
	print "[RagnarokServer]-> Ragnarok Online client ($index) connected.\n";	
}

sub onClientExit 
{
	my ($self, $client, $index) = @_;
	
	$self->{challengeNum} = 0;
	
	print "[RagnarokServer]-> Ragnarok Online client ($index) disconnected.\n";
}

## constants
my $accountID = pack("a4", "acct");
my $posX = 53;
my $posY = 113;

## Globals
my $charID = pack("a4", "char");
my $sessionID = pack("a4", "sess");
my $sessionID2 = pack("C4", 0xff);
my $npcID1 = pack("a4", "npc1");
my $npcID0 = pack("a4", "npc2");
my $monsterID = pack("a4", "mon1");
my $itemID = pack("a4", "itm1");

sub DecryptMessageID 
{
	my ($MID) = @_;
	
	# Checking if Decryption is Activated
	if ($enc_val1 != 0 && $enc_val2 != 0 && $enc_val3 != 0) 
	{
		# Saving Last Informations for Debug Log
		my $oldMID = $MID;
		my $oldKey = ($enc_val1 >> 16) & 0x7FFF;
		
		# Calculating the Next Decryption Key
		$enc_val1 = $enc_val1->bmul($enc_val3)->badd($enc_val2) & 0xFFFFFFFF;
	
		# Xoring the Message ID [657BE2h] [0x6E0A]
		$MID = ($MID ^ (($enc_val1 >> 16) & 0x7FFF));

		# Debug Log
		# print sprintf("Decrypted MID : [%04X]->[%04X] / KEY : [0x%04X]->[0x%04X]\n", $oldMID, $MID, $oldKey, ($enc_val1 >> 16) & 0x7FFF);
	}
	
	return $MID;
}

sub onClientData {
	my ($self, $client, $msg, $index) = @_;

	my $packet_id = DecryptMessageID(unpack("v",$msg));
	my $switch = sprintf("%04X", $packet_id);
	
	# Parsing Packet
	ParsePacket($self, $client, $msg, $index, $packet_id, $switch);
}

sub ParsePacket
{
	my ($self, $client, $msg, $index, $packet_id, $switch) = @_;

	#my $packed_switch = quotemeta substr($msg, 0, 2);
	my $packed_switch = $packet_id;
	
	### These variables control the account information ###
	my $host = $self->getHost();
	my $port = pack("v", $self->getPort());
	$host = '127.0.0.1' if ($host eq 'localhost');
	my @ipElements = split /\./, $host;

	print "Received packet: $switch\n";
	
	# Note:
	# The switch packets are pRO specific and assumes the use of secureLogin 1. It may or may not work with other
	# countries' clients (except probably oRO). The best way to support other clients would be: use a barebones
	# eAthena or Freya as the emulator, or figure out the correct packet switches and include them in the
	# if..elsif..else blocks.

	if (($switch eq '01DB') || ($switch eq '0204')) { # client sends login packet 0204 packet thanks to elhazard

		# '01DC' => ['secure_login_key', 'x2 a*', [qw(secure_key)]],
		my $data = pack("C*", 0xdc, 0x01, 0x14) . pack("x17");
		$client->send($data);

		# save servers.txt info
		my $code = substr($msg, 2);
		if (length($msg) == 2) {
			$clientdata{$index}{secureLogin_type} = 0;
		} elsif (length($msg) == 20) {
			if ($code eq pack("C*", 0x04, 0x02, 0x7B, 0x8A, 0xA8, 0x90, 0x2F, 0xD8, 0xE8, 0x30, 0xF8, 0xA5, 0x25, 0x7A, 0x0D, 0x3B, 0xCE, 0x52)) {
				$clientdata{$index}{secureLogin_type} = 1;
			} elsif ($code eq pack("C*", 0x04, 0x02, 0x27, 0x6A, 0x2C, 0xCE, 0xAF, 0x88, 0x01, 0x87, 0xCB, 0xB1, 0xFC, 0xD5, 0x90, 0xC4, 0xED, 0xD2)) {
				$clientdata{$index}{secureLogin_type} = 2;
			} elsif ($code eq pack("C*", 0x04, 0x02, 0x42, 0x00, 0xB0, 0xCA, 0x10, 0x49, 0x3D, 0x89, 0x49, 0x42, 0x82, 0x57, 0xB1, 0x68, 0x5B, 0x85)) {
				$clientdata{$index}{secureLogin_type} = 3;
			} elsif ($code eq ("C*", 0x04, 0x02, 0x22, 0x37, 0xD7, 0xFC, 0x8E, 0x9B, 0x05, 0x79, 0x60, 0xAE, 0x02, 0x33, 0x6D, 0x0D, 0x82, 0xC6)) {
				$clientdata{$index}{secureLogin_type} = 4;
			} elsif ($code eq pack("C*", 0x04, 0x02, 0xc7, 0x0A, 0x94, 0xC2, 0x7A, 0xCC, 0x38, 0x9A, 0x47, 0xF5, 0x54, 0x39, 0x7C, 0xA4, 0xD0, 0x39)) {
				$clientdata{$index}{secureLogin_type} = 5;
			}
		} else {
			$clientdata{$index}{secureLogin_requestCode} = getHex($code);
		}

	} elsif (($switch eq '01DD') || ($switch eq '01FA') || ($switch eq '0064') || ($switch eq '0060') || ($switch eq '0277') || ($switch eq '02B0')) { # 0064 packet thanks to abt123

#		#my $data = pack("C*", 0xAD, 0x02, 0x00, 0x00, 0x1E, 0x0A, 0x00, 0x00);
#		#$client->send($data);
		my $sex = 1;
		my $serverName = pack("a20", "Poseidon server"); # server name should be less than or equal to 20 characters
		my $serverUsers = pack("V", @{$self->clients()} - 1);
		# '0069' => ['account_server_info', 'x2 a4 a4 a4 x30 C1 a*',
		# 			[qw(sessionID accountID sessionID2 accountSex serverInfo)]],
		my $data;
		if ($switch eq '01FA') {
			$data = pack("C*", 0x69, 0x00, 0x53, 0x00) . 
				$sessionID . $accountID . $sessionID2 . 
				pack("x30") . pack("C1", $sex) . pack("x4") .
				pack("C*", $ipElements[0], $ipElements[1], $ipElements[2], $ipElements[3]) .
				$port .	$serverName . $serverUsers . pack("x2");
		} else {
			$data = pack("C*", 0x69, 0x00, 0x4F, 0x00) . 
				$sessionID . $accountID . $sessionID2 . 
				pack("C*", 0x00, 0x00, 0x00, 0x00) . 
				pack("x26") . pack("C1", $sex);
				
				print "$data\n";


				$client->send($data);
				
				$data = pack("C*", $ipElements[0], $ipElements[1], $ipElements[2], $ipElements[3]) . 
				$port . $serverName . $serverUsers . pack("x2");
		}

		$client->send($data);

		# save servers.txt info
		$clientdata{$index}{version} = unpack("V", substr($msg, 2, 4));
		$clientdata{$index}{master_version} = unpack("C", substr($msg, length($msg) - 1, 1));
		if ($switch eq '01DD') {
			$clientdata{$index}{secureLogin} = 1;
			undef $clientdata{$index}{secureLogin_account};
		} elsif ($switch eq '01FA') {
			$clientdata{$index}{secureLogin} = 3;
			$clientdata{$index}{secureLogin_account} = unpack("C", substr($msg, 47, 1));
		} else {
			undef $clientdata{$index}{secureLogin};
			undef $clientdata{$index}{secureLogin_type};
			undef $clientdata{$index}{secureLogin_account};
			undef $clientdata{$index}{secureLogin_requestCode};
		}
		if (($switch ne '01DD') && ($switch ne '01FA') && ($switch ne '0064')) {
			$clientdata{$index}{masterLogin_packet} = $switch;
		} else {
			undef $clientdata{$index}{masterLogin_packet};
		}

		if($switch eq '02B0') {	# kRO uses 02B2 as masterLogin packet when we have <langtype>0</langtype> in the clientinfo.xml
								# if other servers do use this packet too that will be a problem.
			$clientdata{$index}{kRO} = 1;
		}

	} elsif (($switch eq '0065') || ($switch eq '0275') || ($msg =~ /^$packed_switch$accountID$sessionID$sessionID2\x0\x0.$/)) { # client sends server choice packet

		# Character List
		SendCharacterList($self, $client, $msg, $index, $switch);

		# save servers.txt info
		if ($switch ne '0065') {
			$clientdata{$index}{gameLogin_packet} = $switch;
		} else {
			undef $clientdata{$index}{gameLogin_packet};
		}

	} elsif ($switch eq '0066') { # client sends character choice packet

		# If Using Packet Encrypted Client
		if ( $self->{type}->{$config{server_type}}->{decrypt_mid_keys} )
		{
			# Enable Decryption
			my @enc_values = split(/\s+/, $self->{type}->{$config{server_type}}->{decrypt_mid_keys});
			($enc_val1, $enc_val2, $enc_val3) = (Math::BigInt->new(@enc_values[0]), Math::BigInt->new(@enc_values[1]), Math::BigInt->new(@enc_values[2]));
		}
		
		# State
		$state = 1;

		$clientdata{$index}{mode} = unpack('C1', substr($msg, 2, 1));

		# '0071' => ['received_character_ID_and_Map', 'a4 Z16 a4 v1', [qw(charID mapName mapIP mapPort)]],
		my $mapName = pack("a16", "moc_prydb1.gat");
		my $data = pack("C*", 0x71, 0x00) . $charID . $mapName . 
			pack("C*", $ipElements[0], $ipElements[1], $ipElements[2], $ipElements[3]) . $port;
		
		$client->send($data);
		
	} elsif ($switch eq  $self->{type}->{$config{server_type}}->{maploginPacket} &&
		(length($msg) == 19) &&
		(substr($msg, 2, 4) eq $accountID) &&
		(substr($msg, 6, 4) eq $charID) &&
		(substr($msg, 10, 4) eq $sessionID)
		) { # client sends the maplogin packet

		SendMapLogin($self, $client, $msg, $index);
		# save servers.txt info
		$clientdata{$index}{serverType} = 0;

	} elsif ($switch eq '0072' &&
		(length($msg) == 19) &&
		(substr($msg, 2, 4) eq $accountID) &&
		(substr($msg, 6, 4) eq $charID) &&
		(substr($msg, 10, 4) eq $sessionID)
		) { # client sends the maplogin packet

		SendMapLogin($self, $client, $msg, $index);
		# save servers.txt info
		$clientdata{$index}{serverType} = 0;

	} elsif ($switch eq '009B' &&
		(length($msg) == 32) &&
		(substr($msg, 3, 4) eq $accountID) &&
		(substr($msg, 12, 4) eq $charID) &&
		(substr($msg, 23, 4) eq $sessionID)
		) { # client sends the maplogin packet

		SendMapLogin($self, $client, $msg, $index);
		# save servers.txt info
		$clientdata{$index}{serverType} = 3;

	} elsif ($switch eq '00F5' &&
		(length($msg) == 29) &&
		(substr($msg, 5, 4) eq $accountID) &&
		(substr($msg, 14, 4) eq $charID) &&
		(substr($msg, 20, 4) eq $sessionID)
		) { # client sends the maplogin packet

		SendMapLogin($self, $client, $msg, $index);
		# save servers.txt info
		$clientdata{$index}{serverType} = 4;

	} elsif ($switch eq '009B' &&
		(length($msg) == 32) &&
		(substr($msg, 9, 4) eq $accountID) &&
		(substr($msg, 15, 4) eq $charID) &&
		(substr($msg, 23, 4) eq $sessionID)
		) { # client sends the maplogin packet

		SendMapLogin($self, $client, $msg, $index);
		# save servers.txt info
		$clientdata{$index}{serverType} = 5;

	} elsif ($switch eq '0072' &&
		(length($msg) == 29) &&
		(substr($msg, 3, 4) eq $accountID) &&
		(substr($msg, 10, 4) eq $charID) &&
		(substr($msg, 20, 4) eq $sessionID)
		) { # client sends the maplogin packet

		SendMapLogin($self, $client, $msg, $index);
		# save servers.txt info
		$clientdata{$index}{serverType} = 6;

	} elsif ($switch eq '0072' &&
		(length($msg) == 34) &&
		(substr($msg, 7, 4) eq $accountID) &&
		(substr($msg, 15, 4) eq $charID) &&
		(substr($msg, 25, 4) eq $sessionID)
		) { # client sends the maplogin packet

		SendMapLogin($self, $client, $msg, $index);
		# save servers.txt info
		$clientdata{$index}{serverType} = 7;

	} elsif ($switch eq '009B' &&
		(length($msg) == 26) &&
		(substr($msg, 4, 4) eq $accountID) &&
		(substr($msg, 9, 4) eq $charID) &&
		(substr($msg, 17, 4) eq $sessionID)
		) { # client sends the maplogin packet

		SendMapLogin($self, $client, $msg, $index);
		# save servers.txt info
		$clientdata{$index}{serverType} = 8;

	} elsif ($switch eq '009B' &&
		(length($msg) == 37) &&
		(substr($msg, 9, 4) eq $accountID) &&
		(substr($msg, 21, 4) eq $charID) &&
		(substr($msg, 28, 4) eq $sessionID)
		) { # client sends the maplogin packet

		SendMapLogin($self, $client, $msg, $index);
		# save servers.txt info
		$clientdata{$index}{serverType} = 9;

	} elsif ($switch eq '0072' &&
		(length($msg) == 26) &&
		(substr($msg, 4, 4) eq $accountID) &&
		(substr($msg, 9, 4) eq $charID) &&
		(substr($msg, 17, 4) eq $sessionID)
		) { # client sends the maplogin packet

		SendMapLogin($self, $client, $msg, $index);
		# save servers.txt info
		$clientdata{$index}{serverType} = 10;

	} elsif ($switch eq '0072' &&
		(length($msg) == 29) &&
		(substr($msg, 5, 4) eq $accountID) &&
		(substr($msg, 14, 4) eq $charID) &&
		(substr($msg, 20, 4) eq $sessionID)
		) { # client sends the maplogin packet

		SendMapLogin($self, $client, $msg, $index);
		# save servers.txt info
		$clientdata{$index}{serverType} = 11;

	} elsif ($switch eq '0094' &&
		(length($msg) == 30) &&
		(substr($msg, 12, 4) eq $accountID) &&
		(substr($msg, 2, 4) eq $charID) &&
		(substr($msg, 6, 4) eq $sessionID)
		) { # client sends the maplogin packet

		SendMapLogin($self, $client, $msg, $index);
		# save servers.txt info
		$clientdata{$index}{serverType} = 12;

	} elsif ($switch eq '0072' &&
		(length($msg) == 29) &&
		(substr($msg, 5, 4) eq $accountID) &&
		(substr($msg, 14, 4) eq $charID) &&
		(substr($msg, 20, 4) eq $sessionID)
		) { # client sends the maplogin packet

		SendMapLogin($self, $client, $msg, $index);
		# save servers.txt info
		$clientdata{$index}{serverType} = "1 or 2";

	} elsif (($switch eq '0436' || $switch eq '022D') &&
		(length($msg) == 19) &&
		(substr($msg, 2, 4) eq $accountID) &&
		(substr($msg, 6, 4) eq $charID) &&
		(substr($msg, 10, 4) eq $sessionID)
		) { # client sends the maplogin packet

		$client->send(pack("v a4", 0x0283, $accountID));
		# mapLogin packet
		$client->send(pack("H536", "eb0206ad09222b56c0050500000f012c010100000000000900000001004e565f42415349430000000000000000080000000f0000000030000000000000000000010054465f444f55424c4500000000000000090000000f0000000131000000000000000000010054465f4d495353000000000000000000070000000f0000000132000100000000000a00010054465f535445414c0000000000000000080000000f0000000133000400000000000a00010054465f484944494e4700000000000000090000000f0000000034000100000000000c00020054465f504f49534f4e00000000000000090000000f0000000135001000000000000a00090054465f4445544f5849465900000000000b0000000f000000008e00040000000100030001004e565f464952535441494400000000000b0000000f00000000d701df145a000200000000d701df145a0003000000003a010100d701df145a0002f13200003a010100b0001900d06b0000b0001800b2110000b102080000000000b202080000000000b0002a003f000000b0002b0000000000b0002e002d000000b000300000000000d9070039020000000000000000000000000000000000000000000000000000233000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"));
		$client->{connectedToMap} = 1;

	} elsif ($msg =~ /^$packed_switch/
		&& $msg =~ /$accountID/
		&& $msg =~ /$charID/
		&& $msg =~ /$sessionID/) { # client sends the maplogin packet (unknown)

		print "Received unsupported map login packet $switch.\n";
		visualDump($msg, "$switch");

		SendMapLogin($self, $client, $msg, $index);
		# save servers.txt info
		undef $clientdata{$index}{serverType};
		#$clientdata{$index}{sendMapLogin} = $msg;

	} elsif ($switch eq '007D') { # client sends the map loaded packet
		my $data;

		# Temporary Hack to Initialized Crypted Client
		if ( $self->{type}->{$config{server_type}}->{decrypt_mid_keys} )
		{
			for ( my $i = 0 ; $i < 64 ; $i++ ) 
			{
				$client->send(pack("C C", 0x70, 0x08));
				
				# Forcedly Calculating the Next Decryption Key
				$enc_val1 = $enc_val1->bmul($enc_val3)->badd($enc_val2) & 0xFFFFFFFF;	
			}
		}		
		
		PerformMapLoadedTasks($self, $client, $msg, $index);
	} elsif (
		( ( ($switch eq '007E') || ($switch eq '035F' || ($switch eq '0360') ) ) && (($clientdata{$index}{serverType} == 0) || ($clientdata{$index}{serverType} == 1) || ($clientdata{$index}{serverType} == 2) || ($clientdata{$index}{serverType} == 6) || ($clientdata{$index}{serverType} == 7) || ($clientdata{$index}{serverType} == 10) || ($clientdata{$index}{serverType} == 11))) ||
		(($switch eq '0089') && (($clientdata{$index}{serverType} == 3) || ($clientdata{$index}{serverType} == 5) || ($clientdata{$index}{serverType} == 8) || ($clientdata{$index}{serverType} == 9))) ||
		(($switch eq '0116') && ($clientdata{$index}{serverType} == 4)) ||
		(($switch eq '00A7') && ($clientdata{$index}{serverType} == 12))
		) { # client sends sync packet
		my $data = pack("C*", 0x7F, 0x00) . pack("V", getTickCount);
		$client->send($data);

		### Check if packet 0228 got tangled up with the sync packet
		if (uc(unpack("H2", substr($msg, 7, 1))) . uc(unpack("H2", substr($msg, 6, 1))) eq '0228') {
			# queue the response (thanks abt123)
			$self->{response} = pack("v", $packet_id) . substr($msg, 8, length($msg)-2);
			$self->{state} = 'requested';
		}

	} elsif ($switch eq '00B2') { # quit to character select screen
			
		SendGoToCharSelection($self, $client, $msg, $index);
			
		# Disable Decryption
		$enc_val1 = 0;
		$enc_val2 = 0;
		$enc_val3 = 0;			
			
	} elsif ($switch eq '0187') { # accountid sync (what does this do anyway?)
		$client->send($msg);

	} elsif ($switch eq '018A') { # client sends quit packet
		
		SendQuitGame($self, $client, $msg, $index);

	} elsif ($switch eq '0228' || $switch eq '09D0') { # client sends game guard sync
		# Queue the response
		# Don't allow other packet's (like Sync) to get to RO server.
		my $length = unpack("v",substr($msg,2,2));
		if ($length > 0) {
			$self->{response} = pack("v", $packet_id) . substr($msg,2,$length);
		} else {
			$self->{response} = pack("v", $packet_id);
		};
		$self->{state} = 'requested';
	
	} elsif ($switch eq '02A7') { # client sends hShield response
		# Queue the response
		$self->{response} = $msg;
		$self->{state} = 'requested';

	} elsif ($switch eq '0258') { # client sent gameguard's challenge request
		# Reply with "gameguard_grant" instead of a 0227 packet. Normally, the server would
		# send a 0227 gameguard challenge to the client, then the client will send the
		# proper 0228 response. Only after that will the server send 0259 to allow the
		# client to continue the login sequence. Since this is just a fake server,
		# there is no need to go through all that and we can do a shortcut.
		if ($self->{challengeNum} == 0) {
			print "Received GameGuard sync request. Client allowed to login account server.\n";
			$client->send(pack("C*", 0x59, 0x02, 0x01));
		} else {
			print "Received GameGuard sync request. Client allowed to login char/map server.\n";
			$client->send(pack("C*", 0x59, 0x02, 0x02));
		}
		$self->{challengeNum}++;

	} elsif ($switch eq '09A1') {
		SendCharacterList($self, $client, $msg, $index, $switch);

	} elsif ($switch eq '08B8') {
		my $seed = 'seed';
		my $data = pack("C*", 0xB9, 0x08);
		$data .= pack("V a4 v", $seed, $accountID, 0);

		$client->send($data);

	} else {
		if ($switch eq '0090' || ($msg =~ /\x90\x0($npcID1|$npcID0)/)) { # npc talk
			undef $clientdata{$index}{npc_talk_code};
			if ($msg =~ /\x90\x0$npcID1/) {
				# Show the kafra image
				SendNpcImageShow($self, $client, $msg, $index, "kafra_04.bmp", 0x02);
				# Show the messages
				SendNPCTalk($self, $client, $msg, $index, $npcID1, "[Kafra]");
				SendNPCTalk($self, $client, $msg, $index, $npcID1, "Welcome to Kafra Corp. We will stay with you wherever you go.");
				SendNPCTalkContinue($self, $client, $msg, $index, $npcID1);
			} else {
				SendNPCTalk($self, $client, $msg, $index, $npcID0, "[Hakore]");
				SendNPCTalk($self, $client, $msg, $index, $npcID0, "Hello! I was examining your RO client's login packets while you were connecting to Poseidon.");
				SendNPCTalkContinue($self, $client, $msg, $index, $npcID0);
			}

		} elsif ($switch eq '00B8') { # npc talk response

			my $npcID = substr($msg, 2, 4);
			my $response = unpack("C1", substr($msg, 6, 1));
			if ($npcID eq $npcID0) {
				if ($response == 1) {
					# Check server info
					SendNPCTalk($self, $client, $msg, $index, $npcID, "[Hakore]");
					SendNPCTalk($self, $client, $msg, $index, $npcID, "Your RO client uses the following server details:");
					SendNPCTalk($self, $client, $msg, $index, $npcID, "^2222DDversion: $clientdata{$index}{version}");
					SendNPCTalk($self, $client, $msg, $index, $npcID, "master_version: $clientdata{$index}{master_version}");
					SendNPCTalk($self, $client, $msg, $index, "serverType: " . ((defined $clientdata{$index}{serverType}) ? $clientdata{$index}{serverType} : 'Unknown'));
					if ($clientdata{$index}{secureLogin}) {
						SendNPCTalk($self, $client, $msg, $index, $npcID, "secureLogin: $clientdata{$index}{secureLogin}");
						if ($clientdata{$index}{secureLogin_requestCode}) {
							SendNPCTalk($self, $client, $msg, $index, $npcID, $npcID, "secureLogin_requestCode: $clientdata{$index}{secureLogin_requestCode}");
						} elsif (defined $clientdata{$index}{secureLogin_type}) {
							SendNPCTalk($self, $client, $msg, $index, $npcID, "secureLogin_type: $clientdata{$index}{secureLogin_type}");
						}
						if ($clientdata{$index}{secureLogin_account}) {
							SendNPCTalk($self, $client, $msg, $index, $npcID, "secureLogin_account: $clientdata{$index}{secureLogin_account}");
						}
					}
					if ($clientdata{$index}{masterLogin_packet}) {
						SendNPCTalk($self, $client, $msg, $index, $npcID, "masterLogin_packet: $clientdata{$index}{masterLogin_packet}");
					}
					if ($clientdata{$index}{gameLogin_packet}) {
						SendNPCTalk($self, $client, $msg, $index, $npcID, "gameLogin_packet: $clientdata{$index}{gameLogin_packet}");
					}
					SendNPCTalkContinue($self, $client, $msg, $index, $npcID);
					
					if (defined $clientdata{$index}{serverType}) {
						$clientdata{$index}{npc_talk_code} = 3;
					} else {
						$clientdata{$index}{npc_talk_code} = 2.5;
					}

				} elsif ($response == 2) {
					# Use storage
					SendNPCTalk($self, $client, $msg, $index, $npcID, "[Hakore]");
					SendNPCTalk($self, $client, $msg, $index, $npcID, "Thank you for the visit. Go and multiply!");
					SendNpcTalkClose($self, $client, $msg, $index, $npcID);
				}

			} elsif ($npcID eq $npcID1) {
				if ($response == 1) {
					# Use storage
					my $data;
					$data .= pack("C2 v1", 0xF0, 0x01, 40) .
						pack("v2 C2 v1 x10", 3, 501, 0, 1, 16) .
						pack("v2 C2 v1 x10", 4, 909, 3, 1, 144);
					$data .= pack("v3", 0xF2, 2, 300);
					SendNpcImageShow($self, $client, $msg, $index, "kafra_04.bmp", 0xFF);
					SendNpcTalkClose($self, $client, $msg, $index, $npcID);
					$client->send($data);

				} elsif ($response == 2) {
					# Use storage
					SendNPCTalk($self, $client, $msg, $index, $npcID, "[Kafra]");
					SendNPCTalk($self, $client, $msg, $index, $npcID, "We Kafra Corp. always try to serve you the best.");
					SendNPCTalk($self, $client, $msg, $index, $npcID, "Please come again.");
					SendNpcTalkClose($self, $client, $msg, $index, $npcID);
				}
			}

		} elsif ($switch eq '00B9') { # npc talk continue
			my $npcID = substr($msg, 2, 4);
			if ($npcID eq $npcID0) {
				if ($clientdata{$index}{npc_talk_code} == 2) {
					# Show NPC response list
					SendNpcTalkResponses($self, $client, $msg, $index, $npcID, "Yes, please:No, thanks:");
					$clientdata{$index}{npc_talk_code} = 3;

				} else {
					SendNPCTalk($self, $client, $msg, $index, $npcID, "[Hakore]");
					if (!$clientdata{$index}{npc_talk_code}) {
						if (!defined $clientdata{$index}{serverType}) {
							SendNPCTalk($self, $client, $msg, $index, $npcID, "However, I regret that Openkore may not currently support your server.");
						} elsif ($clientdata{$index}{serverType} == 7 || $clientdata{$index}{serverType} == 12) {
							SendNPCTalk($self, $client, $msg, $index, $npcID, "However, I regret that Openkore does not yet fully support your server this time.");
						} else {
							SendNPCTalk($self, $client, $msg, $index, $npcID, "Based on my examination, I think Openkore supports your server.");
							SendNPCTalk($self, $client, $msg, $index, $npcID, "I can tell you the possible server details you can use to make Openkore to connect to your server.");
						}
						SendNPCTalkContinue($self, $client, $msg, $index, $npcID);
						$clientdata{$index}{npc_talk_code} = 1;

					} elsif ($clientdata{$index}{npc_talk_code} == 1) {
						if ((!defined $clientdata{$index}{serverType}) || ($clientdata{$index}{serverType} == 7)) {
							SendNPCTalk($self, $client, $msg, $index, $npcID, "Would you still like to hear the details?");
						} else {
							SendNPCTalk($self, $client, $msg, $index, $npcID, "Would you like to hear the details?");
						}
						SendNPCTalkContinue($self, $client, $msg, $index, $npcID);
						$clientdata{$index}{npc_talk_code} = 2;
				
					} elsif ($clientdata{$index}{npc_talk_code} == 2.5) {
						if (!defined $clientdata{$index}{serverType}) {
							SendNPCTalk($self, $client, $msg, $index, $npcID, "As you can see, I can't find a matching serverType for your server.");
							SendNPCTalk($self, $client, $msg, $index, $npcID, "Please make a trial-and-error using all available serverTypes, one of them might be able to work.");
						} elsif ($clientdata{$index}{serverType} == 7 || $clientdata{$index}{serverType} == 12) {
							SendNPCTalk($self, $client, $msg, $index, $npcID, "Like I said, your server is not yet fully supported by Openkore.");
							SendNPCTalk($self, $client, $msg, $index, $npcID, "You can login to the server and do most basic tasks, but you cannot attack, sit or stand, or use skills.");
						}
						SendNPCTalkContinue($self, $client, $msg, $index, $npcID);
						$clientdata{$index}{npc_talk_code} = 4;

					} elsif ($clientdata{$index}{npc_talk_code} == 3) {
						SendNPCTalk($self, $client, $msg, $index, $npcID, "The values of ^2222DDip^000000 and ^2222DDport^000000 can be found on your client's (s)clientinfo.xml.");
						SendNPCTalkContinue($self, $client, $msg, $index, $npcID);
						$clientdata{$index}{npc_talk_code} = 4;

					} elsif ($clientdata{$index}{npc_talk_code} == 4) {
						if (!defined $clientdata{$index}{serverType}) {
							SendNPCTalk($self, $client, $msg, $index, $npcID, "If none of the serverTypes work, please inform the developers about this so we can support your server in future releases of Openkore.");
							SendNPCTalk($self, $client, $msg, $index, $npcID, "Please visit ^2222DDhttp://forums.openkore.com/^000000");
							SendNPCTalk($self, $client, $msg, $index, $npcID, "Thank you.");
						} else {
							if (($clientdata{$index}{serverType} == 7)
								|| ($clientdata{$index}{serverType} == 8)
								|| ($clientdata{$index}{serverType} == 9)
								|| ($clientdata{$index}{serverType} == 10)
								|| ($clientdata{$index}{serverType} == 11)
								|| ($clientdata{$index}{serverType} == 12)
								|| ($clientdata{$index}{masterLogin_packet})
								|| ($clientdata{$index}{gameLogin_packet})
							) {
								SendNPCTalk($self, $client, $msg, $index, $npcID, "Please note that you can only connect to your server using Openkore SVN.");
							} else {
								SendNPCTalk($self, $client, $msg, $index, $npcID, "Openkore v.1.6.6 or later will work on your server.");
							}
							SendNPCTalk($self, $client, $msg, $index, $npcID, "For more info, please visit ^2222DDhttp://www.openkore.com/^000000");
							SendNPCTalk($self, $client, $msg, $index, $npcID, "Good luck!");
						}
						SendNpcTalkClose($self, $client, $msg, $index, $npcID);
					}
				}

			} elsif ($npcID eq $npcID1) {
				# Show kafra response list
				SendNpcTalkResponses($self, $client, $msg, $index, $npcID, "Use Storage:Cancel:");
			}

		} elsif ($switch eq '0146') { # talk cancel
			my $npcID = substr($msg, 2, 4);
			if ($npcID eq $npcID1) {
				SendNpcImageShow($self, $client, $msg, $index, "kafra_04.bmp", 0xFF);
			}

		} elsif ($clientdata{$index}{mode}) {

			if (($switch eq '00F7' || $switch eq '0193') && (length($msg) == 2)) { # storage close
				my $data = pack("v1", 0xF8);
				$client->send($data);

			} elsif ($switch eq '00BF') { # emoticon
				my ($client, $code) = @_;
				my $data = pack("v1 a4", 0xC0, $accountID) . substr($msg, 2, 1);
				$clientdata{$index}{emoticonTime} = time;
				$client->send($data);

			} else {
				print "\nReceived packet $switch:\n";
				visualDump($msg, "$switch");

				# Just provide feedback in the RO Client about the unhandled packet
				# '008E' => ['self_chat', 'x2 Z*', [qw(message)]],
				my $data = pack("v2 a31", 0x8E, 35, "Sent packet $switch (" . length($msg) . " bytes).");
				if (timeOut($clientdata{$index}{emoticonTime}, 1.8)) {
					$clientdata{$index}{emoticonTime} = time;
					$data .= pack("v1 a4 C1", 0xC0, $accountID, 1);
				}

				# These following packets should reset the item inventory.
				# If you drop something from your inventory and the server didn't respond,
				# you will not be able to drop the item for the second test
				# This, however, does not cover item_use. YOu would have to relog
				# to test another item_use packet.
				#$data .= pack("v3", 0xAF, 3, 0);
				#$data .= pack("v3", 0xAF, 4, 0);

				# There are no other send packet that contains NPC ids as the last four byte
				# other than the talk and sendGetPlayerInfo packets.
				# Since most possible talk packets are handled above, we can assume that this is
				# a sendGetPlayerInfo packet.
				# Note that we have an NPC that is not named initially to allow a
				# sendGetPlayerInfo packet to be captured.)
				# '0095' => ['actor_info', 'a4 Z24', [qw(ID name)]],
				my $ID = substr($msg, length($msg) - 4, 4);
				if ($ID eq $npcID0) {
					$data .= pack("v1 a4 a24", 0x95, $npcID0, "Server Details Guide");
				} elsif ($ID eq $npcID1) {
					$data .= pack("v1 a4 a24", 0x95, $npcID1, "Kafra");
				}

				$client->send($data);
			}
		}
	}
}

# PACKET SENDING S->C

sub SendCharacterList
{
	my ($self, $client, $msg, $index, $switch) = @_;
	
	# Log
	print "Requested Char List (Standard)\n";
	if ($switch eq '0065') {
		my $blocksize = $self->{type}->{$config{server_type}}->{charBlockSize} || 116; #defaults to 116
		my $totalslots = 12;
		my $data;
		
		$data = pack("V", getTickCount);
		
		$client->send($data);
		
		$data = pack("C*", 0x2D, 0x08);
		$data .= pack("C*", 0x1D, 0x00);
		$data .= pack("C*", 0x0C, 0x00, 0x00, 0x0C, 0x0C);
		$data .= pack("x20");

		print "$data\n";
		
		print "Wanted CharBlockSize : $blocksize\n";		
		#print "Built CharBlockSize : " . length($block) . "\n";

		$client->send($data);

		$data = pack("C3 x3", 0xA0, 0x09, 0x01);
		$client->send($data);

	} elsif ($switch eq '09A1') {
		# Wanted Block Size
		my $blocksize = $self->{type}->{$config{server_type}}->{charBlockSize} || 116; #defaults to 116

		# Packet Len, Total Characters and Total Slots
		my $totalchars = 2;
		my $totalslots = 12;
		my $len = $blocksize * $totalchars;
	
		# Character Block Pack String
		my $packstring = '';

		$packstring = 'a4 V9 v V2 v14 Z24 C8 v Z16 V x4 x4 x4' if $blocksize == 144;
		$packstring = 'a4 V9 v V2 v14 Z24 C8 v Z16 x4 x4' if $blocksize == 136;
		$packstring = 'a4 V9 v V2 v14 Z24 C8 v Z16 x4' if $blocksize == 132;
		$packstring = 'a4 V9 v V2 v14 Z24 C8 v Z16' if $blocksize == 128;
		$packstring = 'a4 V9 v V2 v14 Z24 C6 v2 x4' if $blocksize == 116;
		$packstring = 'a4 V9 v V2 v14 Z24 C6 v2' if $blocksize == 112;
		$packstring = 'a4 V9 v17 Z24 C6 v2' if $blocksize == 108;
		$packstring = 'a4 V9 v17 Z24 C6 v' if $blocksize == 106;
	
		# Unknown CharBlockSize
		if ( length($packstring) == 0 ) { print "Unknown CharBlockSize : $blocksize\n"; return; }
	
		# Character Block Format
		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) = 0;

		# Preparing Begin of Character List Packet
		my $data;
		$data = pack("C2 v", 0x9D, 0x09, $len+4);
=pod
		if ($self->{type}->{$config{server_type}}->{charListPacket} eq '0x82d') {
			$data = $accountID . pack("v2 C5 a20", 0x82d, $len + 29,$totalchars,0,0,0,$totalchars,-0); # 29 = v2 C5 a20 size for bRO
		} else {
			$data = $accountID . pack("v v C3", 0x6b, $len + 7, $totalslots, -1, -1);
		}
=cut
	
		# Character Block
		my $block;
	
		# Filling Character 1 Block
		$cID = $charID;	$hp = 10000; $maxHp = 10000; $sp = 10000; $maxSp = 10000; $hairstyle = 1; $level = 99; $headTop = 0; $hairColor = 6;
		$name = "Poseidon"; $str = 1; $agi = 1; $vit = 1; $int = 1; $dex = 1; $luk = 1;	$exp = 1; $zeny = 1; $jobExp = 1; $jobLevel = 50; $slot = 0; $rename = 0;
	
		# Preparing Character 1 Block
		$block = pack($packstring,$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);

		# Attaching Block
		$data .= $block;
	
		# Filling Character 2 Block
		$cID = $charID; $hp = 10000; $maxHp = 10000; $sp = 10000; $maxSp = 10000; $hairstyle = 1; $level = 99; $headTop = 0; $hairColor = 6;
		$name = "Poseidon Dev"; $str = 1; $agi = 1; $vit = 1; $int = 1; $dex = 1; $luk = 1;	$exp = 1; $zeny = 1; $jobExp = 1; $jobLevel = 50; $slot = 1; $rename = 0;
	
		# Preparing Character 2 Block
		$block = pack($packstring,$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);		
	
		# Attaching Block
		$data .= $block;		
	
		# Measuring Size of Block
		print "Wanted CharBlockSize : $blocksize\n";		
		print "Built CharBlockSize : " . length($block) . "\n";

		$client->send($data);

		#pinCode
		my $seed = 'seed';
		$data = pack("C*", 0xB9, 0x08);
		$data .= pack("V a4 v", $seed, $accountID, 1);

		$client->send($data);
	}
}

sub SendMapLogin {
	my ($self, $client, $msg, $index) = @_;

	# '0073' => ['map_loaded','x4 a3',[qw(coords)]]
	my $data;
	
	if ( $config{server_type} !~ /^bRO/ ) { $data .= pack("C*", 0x83, 0x02) . $accountID; } #<- This is Server Type Based !!
	$data .= pack("C*", 0xEB, 0x02) . pack("V", getTickCount) . getCoordString($posX, $posY, 1) . pack("C*", 0x05, 0x05) . pack("C*", 0x05, 0x05);

	if ($clientdata{$index}{mode}) {
		$data .= pack("C2 v1", 0x0F, 0x01, 226) .
			# skillID targetType level sp range skillName
			pack("v2 x2 v3 a24 C1", 1, 0, 9, 0, 1, "NV_BASIC" . chr(0) . "GetMapInfo" . chr(0x0A), 0) .
			pack("v2 x2 v3 a24 C1", 24, 4, 1, 10, 10, "AL_RUWACH", 0) . # self skill test
			pack("v2 x2 v3 a24 C1", 25, 2, 1, 10, 9, "AL_PNEUMA", 0) . # location skill test
			pack("v2 x2 v3 a24 C1", 26, 4, 2, 9, 1, "AL_TELEPORT", 0) . # self skill test
			pack("v2 x2 v3 a24 C1", 27, 2, 4, 26, 9, "AL_WARP", 0) . # location skill test
			pack("v2 x2 v3 a24 C1", 28, 16, 10, 40, 9, "AL_HEAL", 0); # target skill test
	}
	
	$client->send($data);
	
	$client->{connectedToMap} = 1;	
}

sub SendGoToCharSelection
{
	my ($self, $client, $msg, $index) = @_;
	
	# Log	
	print "Requested Char Selection Screen\n";	
	
	$client->send(pack("v v", 0xB3, 1));
}

sub SendQuitGame
{
	my ($self, $client, $msg, $index) = @_;
	
	# Log
	print "Requested Quit Game...\n";
	
	$client->send(pack("v v", 0x18B, 0));	
}

sub SendLookTo
{
	my ($self, $client, $msg, $index, $ID, $to) = @_;
	
	# Make Poseidon look to front
	$client->send(pack('v1 a4 C1 x1 C1', 0x9C, $ID, 0, $to));
}

sub SendUnitInfo		
{
	my ($self, $client, $msg, $index, $ID, $name) = @_;
	
	# Let's not wait for the client to ask for the unit info
	# '0095' => ['actor_info', 'a4 Z24', [qw(ID name)]],
	$client->send(pack("v1 a4 a24", 0x95, $ID, $name));
}

sub SendSystemChatMessage
{
	my ($self, $client, $msg, $index, $message) = @_;
	
	# '009A' => ['system_chat', 'v Z*', [qw(len message)]],
	$client->send(pack("v2 a32", 0x9A, 36, $message));
}

sub SendShowNPC
{
	my ($self, $client, $msg, $index, $obj_type, $GID, $SpriteID, $X, $Y, $MobName) = @_;
	
	# Packet Structure
	my ($object_type,$NPCID,$walk_speed,$opt1,$opt2,$option,$type,$hair_style,$weapon,$lowhead,$shield,$tophead,$midhead,$hair_color,$clothes_color,$head_dir,$guildID,$emblemID,$manner,$opt3,$stance,$sex,$xSize,$ySize,$lv,$font,$name) = 0;

	# Building NPC Data
	$object_type = $obj_type;
	$NPCID = $GID;
	$walk_speed = 0x1BD;
	$type = $SpriteID;
	$lv = 1;
	$name = $MobName;
	
	# '0856' => ['actor_exists', '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 lv font name)]], # -1 # spawning provided by try71023
	my $dbuf;
	if ( $config{server_type} !~ /^bRO/ ) { $dbuf .= pack("C", $object_type); } #<- This is Server Type Based !!
	$dbuf .= pack("a4 v3 V v11 a4 a2 v V C2",$NPCID,$walk_speed,$opt1,$opt2,$option,$type,$hair_style,$weapon,$lowhead,$shield,$tophead,$midhead,$hair_color,$clothes_color,$head_dir,$guildID,$emblemID,$manner,$opt3,$stance,$sex);
	$dbuf .= getCoordString($X, $Y, 1);
	$dbuf .= pack("C2 v2",$xSize,$ySize,$lv,$font);
	$dbuf .= pack("Z" . length($name),$name);
	my $opcode;
	if ( $config{server_type} !~ /^bRO/ ) { $opcode = 0x858; } #<- This is Server Type Based !!
	$client->send(pack("v v",$opcode,length($dbuf) + 4) . $dbuf);
}

sub SendShowItemOnGround
{
	my ($self, $client, $msg, $index, $ID, $SpriteID, $X, $Y) = @_;
	
	# '009D' => ['item_exists', 'a4 v1 x1 v3', [qw(ID type x y amount)]]
	$client->send(pack("v1 a4 v1 x1 v3 x2", 0x9D, $ID, $SpriteID, $posX + 1, $posY - 1, 1));	
}

sub SendNPCTalk
{
	my ($self, $client, $msg, $index, $npcID, $message) = @_;
	
	# '00B4' => ['npc_talk', 'v a4 Z*', [qw(len ID msg)]]
	my $dbuf = pack("a" . length($message), $message);
	$client->send(pack("v2 a4", 0xB4, (length($dbuf) + 8), $npcID) . $dbuf);
}

sub SendNPCTalkContinue
{
	my ($self, $client, $msg, $index, $npcID) = @_;
	
	# '00B5' => ['npc_talk_continue', 'a4', [qw(ID)]]
	$client->send(pack("v a4", 0xB5, $npcID));
}

sub SendNpcTalkClose
{
	my ($self, $client, $msg, $index, $npcID) = @_;
	
	# '00B6' => ['npc_talk_close', 'a4', [qw(ID)]]
	$client->send(pack("v a4", 0xB6, $npcID));	
}

sub SendNpcTalkResponses
{
	my ($self, $client, $msg, $index, $npcID, $message) = @_;
	
	# '00B7' => ['npc_talk', 'v a4 Z*', [qw(len ID msg)]]
	my $dbuf = pack("a" . length($message), $message);
	$client->send(pack("v2 a4", 0xB7, (length($dbuf) + 8), $npcID) . $dbuf);	
}

sub SendNpcImageShow
{
	my ($self, $client, $msg, $index, $image, $type) = @_;

	# Type = 0xFF = Hide Image
	# Type = 0x02 = Show Image
	# '01B3' => ['npc_image', 'Z64 C', [qw(npc_image type)]]
	$client->send(pack("v a64 C1", 0x1B3, $image, $type));
}

# SERVER TASKS

sub PerformMapLoadedTasks
{
	my ($self, $client, $msg, $index) = @_;
	
	# Looking to Front
	SendLookTo($self, $client, $msg, $index, $accountID, 4);
	
	# Let's not wait for the client to ask for the unit info
	SendUnitInfo($self, $client, $msg, $index, $accountID, 'Poseidon' . (($clientdata{$index}{mode} ? ' Dev' : '')));
	
	# Global Announce
	SendSystemChatMessage($self, $client, $msg, $index, "Welcome to the Poseidon Server !");

	# Show an NPC
	SendShowNPC($self, $client, $msg, $index, 1, $npcID0, 86, $posX + 3, $posY + 4, "Server Details Guide");
	SendLookTo($self, $client, $msg, $index, $npcID0, 3);
	SendUnitInfo($self, $client, $msg, $index, $npcID0, "Server Details Guide");

	# Dev Mode (Char Slot 1)
	if ($clientdata{$index}{mode}) 
	{
		# Show an NPC (Kafra)
		SendShowNPC($self, $client, $msg, $index, 1, $npcID1, 114, $posX + 5, $posY + 3, "Kafra NPC");
		SendLookTo($self, $client, $msg, $index, $npcID1, 4);
		SendUnitInfo($self, $client, $msg, $index, $npcID1, "Kafra NPC");			
		
		# Show a monster
		SendShowNPC($self, $client, $msg, $index, 5, $monsterID, 1002, $posX - 2, $posY - 1, "Poring");
		SendLookTo($self, $client, $msg, $index, $monsterID, 3);
		SendUnitInfo($self, $client, $msg, $index, $monsterID, "Poring");
		
		# Show an item on ground
		SendShowItemOnGround($self, $client, $msg, $index, $itemID, 512, $posX + 1, $posY - 1);
	}
}

1;


zonda
Human
Human
Posts: 45
Joined: 12 Aug 2014, 21:15
Noob?: Yes

Re: pRO's Update! Login Pincode..(similar to bRO)

#193 Post by zonda »

thanks for all the work bro... i'm doing some testing now. i saw something on youtube on how you can connect multiple bots to 1 poseidon server. you might want to check it out as well

https://www.youtube.com/watch?v=ixTO5d-tn54
jkcorp
Noob
Noob
Posts: 4
Joined: 14 Aug 2014, 02:42
Noob?: No

Re: pRO's Update! Login Pincode..(similar to bRO)

#194 Post by jkcorp »

Hi Brokenbokeh,
There you go, i was able to go through...

What type of Virtual Machine are you using to run poseidon?
brokenbokeh
Plain Yogurt
Plain Yogurt
Posts: 50
Joined: 08 Aug 2014, 03:02
Noob?: No

Re: pRO's Update! Login Pincode..(similar to bRO)

#195 Post by brokenbokeh »

I am using VMWare Player.
zonda
Human
Human
Posts: 45
Joined: 12 Aug 2014, 21:15
Noob?: Yes

Re: pRO's Update! Login Pincode..(similar to bRO)

#196 Post by zonda »

i tried using the f2pexe but it connects me to the real game, tried removing the 5free5 and i get this screen...

Image

so i cant select a char. ill try downloading openkore again in my vmware and test it there
jkcorp
Noob
Noob
Posts: 4
Joined: 14 Aug 2014, 02:42
Noob?: No

Re: pRO's Update! Login Pincode..(similar to bRO)

#197 Post by jkcorp »

Hi brokenbokeh,
Great Thanks~ I Appreciate it.

I'm using Windows Virtual PC to run Poseidon.
I'm still trying to sort out some ways to run openkore without initializing poseidon
I'll keep u updated guys
brokenbokeh
Plain Yogurt
Plain Yogurt
Posts: 50
Joined: 08 Aug 2014, 03:02
Noob?: No

Re: pRO's Update! Login Pincode..(similar to bRO)

#198 Post by brokenbokeh »

Hmm, This is the text on the Target of my shortcut on the desktop. It works perfectly fine for me.

"C:\Program Files\Level Up Games\Ragnarok Online\f2pexe.exe" 1rag1 5free5 /account:poseidon.xml
zonda
Human
Human
Posts: 45
Joined: 12 Aug 2014, 21:15
Noob?: Yes

Re: pRO's Update! Login Pincode..(similar to bRO)

#199 Post by zonda »

looks like I have it working now. gameguard still pops up with the error though and I get the 09cf code and bot disconnects...

have vmware up now though. downloading openkore...

do I need just the openkore or poseidon in the virtual machine? also did you make any other changes to openkore_bot\src\Network\Receive\pRO..pm??
brokenbokeh
Plain Yogurt
Plain Yogurt
Posts: 50
Joined: 08 Aug 2014, 03:02
Noob?: No

Re: pRO's Update! Login Pincode..(similar to bRO)

#200 Post by brokenbokeh »

I run poseidon and openkore in the virtual machine

Here is what my pRO.pm looks like.

Code: Select all

#########################################################################
#  OpenKore - Network subsystem
#  Copyright (c) 2006 OpenKore Team
#
#  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.
#########################################################################
# pRO (Philippines)
# Servertype overview: http://wiki.openkore.com/index.php/ServerType
package Network::Receive::pRO;

use strict;
use base qw(Network::Receive::ServerType0);

use Globals;
use Log qw(message warning error debug);
use Translation;
use Misc;
use Utils qw(timeOut getFormattedDate);
use I18N qw(bytesToString stringToBytes);

use Time::HiRes qw(time);

sub new {
	my ($class) = @_;
	my $self = $class->SUPER::new(@_);
	my %packets = (
		#'006D' => ['character_creation_successful', 'a4 V9 v V2 v14 Z24 C6 v2', [qw(charID exp zeny exp_job lv_job opt1 opt2 option stance manner points_free hp hp_max sp sp_max walk_speed type hair_style weapon lv points_skill lowhead shield tophead midhead hair_color clothes_color name str agi vit int dex luk slot renameflag)]],
		'0097' => ['private_message', 'v Z24 V Z*', [qw(len privMsgUser flag privMsg)]], # -1
		#'082D' => ['received_characters_info', 'x2 C5 x20', [qw(normal_slot premium_slot billing_slot producible_slot valid_slot)]],
		#'099D' => ['received_characters', 'v a*', [qw(len charInfo)]],
	);

	foreach my $switch (keys %packets) {
		$self->{packet_list}{$switch} = $packets{$switch};
	}

	my %handlers = qw(
		received_characters 099D
		actor_exists 0856
		actor_connected 0857
		actor_moved 0858
		account_id 0283
	);
	$self->{packet_lut}{$_} = $handlers{$_} for keys %handlers;
	
	return $self;
}

=pod
sub received_characters_info {
	my ($self, $args) = @_;

	Scalar::Util::weaken(my $weak = $self);
	my $timeout = {timeout => 6, time => time};

	$self->{charSelectTimeoutHook} = Plugins::addHook('Network::serverConnect/special' => sub {
		if ($weak && timeOut($timeout)) {
			$weak->received_characters({charInfo => '', RAW_MSG_SIZE => 4});
		}
	});

	$self->{charSelectHook} = Plugins::addHook(charSelectScreen => sub {
		if ($weak) {
			Plugins::delHook(delete $weak->{charSelectTimeoutHook}) if $weak->{charSelectTimeoutHook};
		}
	});

	$timeout{charlogin}{time} = time;

	$self->received_characters($args);
}


sub received_characters {
	return if ($net->getState() == Network::IN_GAME);
	my ($self, $args) = @_;
	$net->setState(Network::CONNECTED_TO_LOGIN_SERVER);

	$charSvrSet{normal_slot} = $args->{normal_slot} if (exists $args->{normal_slot});
	$charSvrSet{premium_slot} = $args->{premium_slot} if (exists $args->{premium_slot});
	$charSvrSet{billing_slot} = $args->{billing_slot} if (exists $args->{billing_slot});
	$charSvrSet{producible_slot} = $args->{producible_slot} if (exists $args->{producible_slot});
	$charSvrSet{valid_slot} = $args->{valid_slot} if (exists $args->{valid_slot});

	undef $conState_tries;

	Plugins::callHook('parseMsg/recvChars', $args->{options});
	if ($args->{options} && exists $args->{options}{charServer}) {
		$charServer = $args->{options}{charServer};
	} else {
		$charServer = $net->serverPeerHost . ":" . $net->serverPeerPort;
	}

	# PACKET_HC_ACCEPT_ENTER2 contains no character info
	return unless exists $args->{charInfo};

	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 = $self->received_characters_unpackString;
		# 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) =
			unpack($unpack_string, substr($args->{RAW_MSG}, $i));
		$chars[$slot] = new Actor::You;

		# Re-use existing $char object instead of re-creating it.
		# Required because existing AI sequences (eg, route) keep a reference to $char.
		$chars[$slot] = $char if $char && $char->{ID} eq $accountID && $char->{charID} eq $cID;

		$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]{deleteDate} = getFormattedDate($deleteDate) if ($deleteDate);
		$chars[$slot]{nameID} = unpack("V", $chars[$slot]{ID});
		$chars[$slot]{name} = bytesToString($chars[$slot]{name});
	}

	my $nChars = 0;
	foreach (@chars) { $nChars++ if($_); }

	# FIXME better support for multiple received_characters packets
	if ($args->{switch} eq '099D' && $args->{RAW_MSG_SIZE} >= ($blockSize * 3)) {
		$net->setState(1.5);
		return;
	}

	message T("Received characters from Character Server\n"), "connection";

	if (charSelectScreen(1) == 1) {
			$firstLoginMap = 1;
			$startingzeny = $chars[$config{'char'}]{'zeny'} unless defined $startingzeny;
			$sentWelcomeMessage = 1;
	}
}
=cut

*parse_quest_update_mission_hunt = *Network::Receive::ServerType0::parse_quest_update_mission_hunt_v2;
*reconstruct_quest_update_mission_hunt = *Network::Receive::ServerType0::reconstruct_quest_update_mission_hunt_v2;

1;