#!/usr/bin/perl -w

use strict;

my $show_op_code = 0;
my $show_xy_hex = 1;

my $my_addr = "(80.xxx.xxx.xxx)|(dikiy.xxx.tld)";
my $rem_addr = "218.153.120.\\d+";
my $buf;
my $dir;

$|++;

my %mob_n = (
	x04 => "Elite Bull?",
	x07 => "Titan?",
	x0b => "Ghost",
	x0c => "POISON RAT",
	x0d => "LARGE SPIDER",
	x10 => "Elite skeleton",
	x13 => "Yeti",
	x14 => "Elite Yeti",
	x15 => "Assasin",
	x16 => "Ice Monster",
	x17 => "Hommerd",
	x18 => "Worm",
	x19 => "Ice Queen"
);

my %wear = (
	0 => "bronze",
	1 => "dragon",
	2 => "pad",
	3 => "DW-COOLEST",
	4 => "bone",
	5 => "leather",
	6 => "scale",
	8 => "brass",
	9 => "plate?",

	a => "wine",
	b => "silk",
	c => "wind",
	d => "spirit",
	e => "COOLER-THEN-GREEN?",

	f => "NONE"
);

my %class = (
	0 => "Dark Wizard",
	1 => "MEGA Wizard ?",
	2 => "Dark Knight",
	3 => "Night Blade ?",
	4 => "Elf",
	5 => "MEGA Elf",
	6 => "Magic Gladiator"
);

my %position = (
	0 => "stand",
	1 => "UNKNOWN_POSITION",
	2 => "sit",
	3 => "walled",
	4 => "hanged"
);

my %damage = (
	0 => "hited",
	3 => "CRIT! hited"
);

my %weapon = (
	x05 => "Blade",
	x06 => "Gladius",
	x20 => "Small Axe",
	
	x60 => "Laser Spear",

	x84 => "Tiger Bow",
	x8f => "Arrows",

	xc2 => "Kite shield",
	xc0 => "Round shield",
	xc5 => "Plate shield?",

	xff => "NONE"
);

my %pet = (
	c => "angel",
	d => "satan",
	e => "horn",
	f => "NONE"
);

my %wind = (
	0 => "no",
	1 => "yes"
);

while (<>) {
	if (m!^([\w.]+)\.\w+ > ([\w.]+)\.\w+!) {
		parse ($buf) if defined $buf;
		undef $buf;
		$dir = "$1 > $2";
		$dir =~ s/$my_addr/me/;
		$dir =~ s/$rem_addr/serv/;
	}
	if ( m!^0x\w+\s+([0-9a-f ]+)*!g ) {
		my $str = $1;
		$str =~ s/ //g;
		$buf .= $str;
	}
}

sub parse {
	my $packet = shift;
	$packet =~ s/^.{80}//;
	unless ($packet) {
		print "$dir ACK\n";
		return;
	}
	if ( $packet !~ m/^c[12]/ ) {
		print "Bad MU packet format. Skiping. [$packet]\n";
		return;
	}
	print "$dir\n";
	while ($packet) {
		my $length;
		if ( $packet =~ s!^c(1)(\w{2})!! ) {
			$length = hex $2;
		} elsif ( $packet =~ s!^c(2)(\w{4})!! ) {
			$length = hex $2;
		} elsif ( $packet =~ s!^c(3)(\w{2})!! ) {
			print "Skip C3 msg [". substr ($packet, 0, hex($2)*2-4,"") ."]\n";
			next;
		} else {
			print "Bad MU packet format. Skiping. [$packet]\n";
			undef $packet;
			next;
		}
		my $msg = substr $packet, 0, $length*2 - (1+$1)*2 , "";
		message ($msg);
	}
}

sub hex2str {
	my $str =shift;
	$str =~ s!(\w\w)!$1 !g;
	return join "", map { chr hex } split(/ /, $str);
}

sub dec2hex {
	my $dec = shift;
	my @a = (0..9, 'a'..'f');
	my $b = int $dec/16;
	return $a[$b] . $a[ $dec-$b*16 ];
}

sub recode {
	my $str = shift;
	return $str;
}

sub ifstr {
	my $a = shift;
	my $b = shift;
	return $a?$a:$b;
}

sub XY {
	my $data = shift;
	$data =~ m!^(..)(..)$! || return "BAD_XY";
	if ($show_xy_hex) {
		return "$1,$2"
	} else {
		return hex("x$1") .",". hex("x$2");
	}
}

sub message {
	my $msg = shift;
	my ($code, $data);
	my $str;

	$msg =~ m!(\w{2})(.*)! && do {
		$code = hex $1; $data = $2;
		$str = "$1:$2";
	};

	my $srv = ($dir =~ /^me/) ? 0 : 1;

	# public speach
	$code == 0x00 && $srv && do {
			my $tmp = hex2str ($data);
			my $name = substr ($tmp, 0, 10, "");
			$name =~ s!\x00+$!!g;
			$tmp =~ s!\x00+$!!g;
			$str =  "$name say '". recode($tmp). "'";
		};
	$code == 0x00 && !$srv && do {
			$str = "ME send: $data ". hex2str($data);
			#join("--", unpack("B*", hex2str($data)));
		};

	# move to
	$code == 0xd4 && $srv && do {
			$data =~ m!^(....)(....)!;
			$str = "Move ID:$1 @ ". XY($2);
		};

	# damage
	$code == 0x11 && $srv && do {
			$data =~ m!^(....)(....)(..)!;
			$str = "Damage: ID:$1 ". ifstr($damage{hex "x$3"},"UNKNOWN($3)")." on ". hex ($2) ."HP [$data]";
		};

	# die
	$code == 0x17 && $srv && do {
			if ($data =~ m!(....)00(....)!) {
				$str = "Death: $1 killed by $2";
			} else {
				$str = "Death: I WAS WRONG! $data"
			}
		};

	# we meet monster
	0x13 == $code && $srv && do {
		my $num = substr($data, 0, 2, ""); $num = hex ("0x$num");
		$str = "We meet $num monsters:";
		for (1..$num) {
			$data =~ m!^(.{4})(..)(.{6})(.{4})(.{4})(..)00!;
			my ($id, $mid, $unkn, $xy1, $xy2, $rest) = ($1, "x$2", $3, $4, $5, $6);
			$str .= sprintf("\n\tMOB %12s ID:$id @ %s->%s [$unkn|$rest]",
				$mob_n{$mid}?$mob_n{$mid}:"unknown($mid)",
				XY($xy1), XY($xy2));
			substr($data, 0, 24, "");
		}
	};

	# we meet character
	0x12 == $code && $srv && do {
		my $num = substr($data, 0, 2, ""); $num = hex ("0x$num");
		$str = "We meet $num characters";
		for (1..$num) {
			$data =~ s!^(.{4})(.{4})!!;
			my ($id, $xy) = ($1, XY($2));
			my $name = substr($data, 14*2, 10*2, "--C-H-A-R--N-A-M-E--");
			my $xy2 = substr($data, 24*2, 2*2, "XXYY"); $xy2 = XY($xy2);
			my $cl = substr($data, 0, 1); $cl = ifstr($class{$cl}, $cl);
			my $pos = substr($data, 1, 1); $pos = ifstr($position{$pos});
			my ($lh, $rh, $helm, $armor, $pants, $gloves, $boots, $pet, $wind, $rest);
			$data =~ m!^..(..)(..)(.)(.)(.)(.)(.)(.)(.)(.{15})! && do {
					$lh = ifstr($weapon{"x$1"}, $1);
					$rh = ifstr($weapon{"x$2"}, $2);
					$helm = ifstr($wear{$3}, $3);
					$armor = ifstr($wear{$4}, $4);
					$pants = ifstr($wear{$5}, $5);
					$gloves = ifstr($wear{$6}, $6);
					$boots = ifstr($wear{$7}, $7);
					$pet = ifstr($pet{$8}, "UNKNOWN($8)");
					$wind = ifstr($wind{$9}, "UNKNOWN($9)");
					$rest = $9; # All other things
				};
			$name = hex2str($name);
			$name =~ s!\x00+$!!g;
			$str .= sprintf ("\n\tchar %10s %10s ID:$id $pos @ %s [%s]",
				$name, $cl,
				($xy eq $xy2 ? "$xy" : "$xy->$xy2"),
				$rest);
			$str .= "\n\t\tWeared: Armor:$armor Helm:$helm Pants:$pants Gloves:$gloves Boots:$boots";
			$str .= "\n\t\tLeftHand: $lh RightHand:$rh Pet:$pet Wind:$wind";
			substr($data,0, 11, "cpLLRRHAPGB");
			$str .= "\n\t\t[". substr($data, 0, 28*2, "") ."]";
		}
	};

	# char list
	$code == 0xf3 && $srv && do {
			"00" eq substr($data,0,2,"") || return;
			my $num = hex substr($data, 0, 2, "");
			unless ($num) { print "   CharList: empty\n"; return;}
			$str = "CharList ($num chars)\n";
			for (1..$num) {
				substr($data,0,2,"");
				my $name = substr ($data, 0, 11*2, "");
				$name = hex2str($name);
				$name =~ s!\x00+$!!;
				print "$name\n";
				my $lvl = hex substr($data, 0, 2, "");
				# skip the rest
				$str .= "     $name ($lvl) [$data]\n";
				substr($data,0,13*2,"");
			}
		};

	# guilds
	0x5a == $code && $srv && do {
		my $num = substr ($data, 0, 1*2, "");
		$str = "Guilds ($num) :";
		for (1..$num) {
			my $id = substr($data, 0, 2*2, "");
			my $gname = substr($data, 0, 8*2, "");
			$gname = hex2str($gname);
			$gname =~ s!^([^\x00]+)\x00.*!$1!;
			
			my $logo;
			for (1..8) {
				my $line = substr($data, 0, 8, "");
				$line =~ tr!0123456789abcdef! 123456789abcde#!;
				$logo .= "\n\t\t$line";
			}
			$str .= "\n\tguild $gname ID:[$id] $logo";
			####substr($data, 0, 42*2, "");
		}
	};

	# bind char to guild
	0x5b == $code && $srv && do {
		my $num = substr($data, 0, 2, ""); $num = hex "x$num";
		$str = "";
		for (1..$num) {
			my $char = substr($data, 0, 2*2, "");
			my $guild = substr($data, 0, 2*2, "");
			$str .= "Char ID:[$char] binded to guild ID:[$guild]\n";
		}
	};

	# head turning ?????
	0x18 == $code && $srv && do {};

	# blue message from server
	0x0d == $code && $srv && do {
			my $len = length($data)-4;
			$data =~ m!.(.{$len})00!;
			$str = "BL_MSG: ". hex2str($1)
		};

	0xfff == $code && $srv && do {
			$str = ">>$data | ". hex2str($data);
		};

	print "   ". ($show_op_code? "(".dec2hex($code).")" : "") ."$str\n";
}
