#!/usr/bin/perl -w
#
# June, 2005
# Scriptwise Source File by Mitch
# 
# version 1 BETA 3
#
# This first version has horrible conventions.
# And is written in a very fuzzy way.

sub BEGIN
{
  if ($^O !~ m/Win/i)
  {
    print "\n".'# You\'re not running on a Windows platform'."\n";
    print "\n".'# The script will end'."\n";
    sleep 3;
    exit;
  }
}

use strict;
use IO::Socket;
use IO::Select;
use Win32::Process;
use Term::ANSIColor;
use FindBin qw($Bin);
use Win32::Console::ANSI;

no strict 'refs';

my $DIR = $Bin;
$DIR =~ s[\\][/]g;
$DIR .= '/' if ($DIR !~ m[/$]);

my $proc;

my @Commands = qw(Get_vars Set_var Rem_var App_var);
push @Commands,qw(Get_filters Set_filter Rem_filter Toggle_filter Load_filter Save_filter);
push @Commands,qw(Anti_error);
push @Commands,qw(Receive Mass_task);
push @Commands,qw(Get_users Get_info Toggle_hc Set_mission);
push @Commands,qw(Toggle_datalog Get_datalog Rem_datalog);
push @Commands,qw(Toggle_chatlog Get_chatlog Rem_chatlog);
push @Commands,qw(Notice Make_talk Mass_talk Set_credits);
push @Commands,qw(Set_scolor Toggle_trade Text2hex Gimme_cam Data Notes Cls Restart Exit About);

my $Title = 'Scriptwise by Mitch © 2005 (v1 BETA 3)';
system 'title '.$Title;
system 'cls';


my $intro = '
   ____   ____   _____   _   _____   _______   _       _   _   ____   _____ 
  |  __| |  __| | ___ | | | | ___ | |__   __| | |     | | | | |  __| |  ___|  
  | |__  | |    |   __| | | |  ___|    | |    | |  _  | | | | | |__  | |__  
  |__  | | |    | | \   | | | |        | |    | | | | | | | | |__  | |  __| 
   __| | | |__  | |\ \  | | | |        | |    | |_| |_| | | |  __| | | |___ 
  |____| |____| |_| \_\ |_| |_|        |_|    |_________| |_| |____| |_____|

 --- www.scriptwise.tk ---- v1 BETA 3 ---- By Mitch --- Don\'t close this ---

';

print colored['bold red'], $_ foreach (split("", $intro));

Message('Please finish the following URL to specify the hotel to load');
my $Hotel = 'www.habbohotel.'.Input('http://www.habbohotel.');
Message('Connecting');
my ($HabboID, $Language) = GetHabboID($Hotel);
my ($RemoteHost, $RemotePort, $LocalPort) = MakeTmpHabbo($Hotel, $Language, $HabboID);
LaunchBrowser();

my $Obj = IO::Socket::INET->new
  (
    LocalHost	=>	'127.0.0.1',
    LocalPort	=>	$LocalPort,
    Proto	=>	'tcp',
    Listen	=>	1,
    Reuse	=>	1,
  ) or die "\n".'# Can\'t listen for client: '.$!;
my $SckClient = $Obj->accept;
my $SckServer = IO::Socket::INET->new
  (
    PeerAddr	=>	$RemoteHost,
    PeerPort	=>	$RemotePort,
    Proto	=>	'tcp',
  ) or die "\n".'# Can\'t connect to server: '.$!;
Message('Connected');
my $Library = IO::Select->new;
$Library->add($SckServer);
$Library->add($SckClient);

########################

my (@Ready, @Arguments, @Vars, @Filters);
my ($Socket, $Data, $Previous, $SplitData);
my ($MyName, $Mode, $Code, $Message, $ID, $User);
my ($Argument);
my $AntiError = 1;
my (%Persona, %IDs);
my %Counters = (
                serverpackets	=>	0,
                serverbytes	=>	0,
                clientpackets	=>	0,
                clientbytes	=>	0,
                conversations	=>	0,
                names		=>	0,
              );
my %Options = (
                datalog		=>	1,
                chatlog		=>	0,
                trade		=>	1,
                stickies	=>	0,
                habbo_club	=>	0,
              );
my %Data = (
             fuse_rights	=>	undef,
           );

my ($_1, $_2, $_4, $_30) = (chr(1), chr(2), chr(4), chr(30));

while (@Ready = $Library->can_read)
{
  foreach $Socket (@Ready)
  {
    sysread $Socket, $Data, 1024;
    if (!$Data)
    {
      close $Socket;
      $Library->remove($Socket);
      Message('Exiting');
    }
    if ($Socket == $SckServer)
    {

      $Data = $Previous.$Data if (defined $Previous);
      if ($Data !~ m/$_1$/)
      {
        $Previous = $Data;
        next;
      }
      else {
        $Previous = '';
      }

      foreach $SplitData (split($_1, $Data))
      {
        $SplitData .= $_1;

        if    ($SplitData =~ m/^\@b(\d+.+)$_1$/)
        {
          foreach my $Move (split("\r", $1))
          {
            $Move =~ s/\r+$//;
            next if (!defined $Move);
            my $id = $1 if ($Move =~ s/^(\d+)\s+//);
            next if (!defined $id);
            my $name = $IDs{$id};
            next if (!defined $name);
            foreach my $Part (split('/', $Move))
            {
              next if (!$Part);
              if    ($Part =~ m/^(?:[\d\.]+,){4}\d+$/)
              {
                $Persona{$name}->{Location} = $Part;
              }
              elsif ($Part =~ m/^flatctrl (.+)$/) {
                $Persona{$name}->{Rights} = $1;
              }
              elsif ($Part =~ m/^(?:carryd|cri) (\d+)$/)
              {
                $Persona{$name}->{CarryingObj} = $1;
              }
            }
            if    (exists $Persona{$name}->{Rights} && $Move !~ m/flatctrl/)
            {
              delete $Persona{$name}->{Rights};
            }
            elsif (exists $Persona{$name}->{CarryingObj}
                   && $Move !~ m/(?:carryd|cri)/) {
              delete $Persona{$name}->{CarryingObj};
            }
          }
        }
        elsif ($SplitData =~ m/^\@\\i:(.+)$_1$/)
        {
          foreach my $Profile (split("\r".'i:', $1))
          {
            my $petid;
            my ($id, $name, $figure, $location, $custom, $sex, $badge)
                = split(/\r.:/, $Profile);
            ($petid, $name) = split($_4, $name) if ($name =~ m/$_4/);
            $name .= ' ('.++$Counters{names}.')'
              if (exists $Persona{$name} && $name ne $MyName);
            $Persona{$name}->{ID} = $id;
            $Persona{$name}->{Sex} = $sex || 'Pet';
            $Persona{$name}->{Name} = $name;
            $Persona{$name}->{Badge} = $badge if (defined $badge);
            $Persona{$name}->{PetID} = $petid if (defined $petid);
            $Persona{$name}->{Figure} = $figure;
            $Persona{$name}->{Location} = $location;
            $Persona{$name}->{CustomData} = $custom || 'undef';
            $IDs{$id} = $name;
            SaveChat('*** '.$name.' has entered the room ***') if ($Options{chatlog} == 1);
          }
        }
        elsif ($SplitData =~ m/^\@([XYZ])([HIJK]|[PQRS][A-Z])(.+?)$_2$_1$/) {
          $Mode = ($1 eq 'X' ? 'says' : $1 eq 'Y' ? 'whispers' : 'shouts');
          $Message = $3;
          $User = $IDs{DecodeHabboID($2)} || 'UNKNOWN';
          ++$Counters{conversations};
          SaveChat($User.' '.$Mode.': '.$Message) if ($Options{chatlog} == 1);

          if ($User eq $MyName
              && $Message =~ m/^:(.+?)(?:\s+(.+))?$/ 
              && length($Message) > 3)
          {

            $Message = ucfirst(lc($1));
            @Arguments = split(m/(?<!\\),\s+/, $2) if (defined $2);
            if (grep $Message eq $_, @Commands)
            {
              foreach (@Arguments)
              {
                if (m/^:terminal$/i)
                {
                  Message('Enter your Hexadecimal');
                  my $var = Input();
                  $var =~ s/[^\s0-9a-fA-F]+//g;
                  if ($var !~ m/^[\s0-9a-fA-F]+$/)
                  {
                    Error('Invalid Hexadecimal value!'."\r".
                          ':terminal value is set to \' \'.');
                    $var = ' ';
                  }
                  else {
                    my $tmp = $var;
                    $var = '';
                    foreach (split(/\s+/, $tmp))
                    {
                      $_ = '0'.$_ while length($_) < 2;
                      $var .= pack("H*", $_);
                    }
                  }
                  s/.+/$var/m;
                  next;
                }
                if (m/var_(\d+)/ && exists $Vars[$1])
                {
                  s<var_(\d+)><$Vars[$1]>g;
                }
                if (m{<[0-9A-F]{1,2}>})
                {
                  s[(?<!\\)<([0-9A-F]{1,2})>][pack("H*", $1)]eg;
                }
                if (m/^(?<!\\):(\d+)(?:\s+)?-(?:\s+)?(\d+)$/)
                {
                  my ($from, $to) = ($1, $2);
                  my @arr = ($from..$to);
                  my $tmp = shift(@arr);
                  push (@Arguments, @arr);
                  s/.+/$tmp/;
                }
                s/\\//g;
              }
              &{$Message}(@Arguments);
              $SplitData = $_1;
            }
            else {
              Error('The command you specified does not exist!'."\r".
                    'Please contact the author if you feel this is wrong.');
            }
          }
        }
        elsif ($SplitData =~ m/^\@](\d+)$_1$/) {
          my $Name = $IDs{$1};
          delete $IDs{$1};
          if (defined $Name && exists $Persona{$Name})
          {
            delete $Persona{$Name};
            SaveChat('*** '.$Name. ' has left the room ***') if ($Options{chatlog} == 1);
          }
        }
        elsif ($SplitData =~ m/^\@v(?:.+?$_2){2}(.+?)$_2/ && $Options{chatlog} == 1) {
          SaveChat('*** Entered room '.$1.' ***') if ($Options{chatlog} == 1);
        }
        elsif ($SplitData =~ m/^AE/) {
          %IDs = ();
          $Counters{names} = 0;
          foreach (keys(%Persona))
          {
            delete $Persona{$_} unless ($_ eq $MyName);
          }
        }
        elsif ($SplitData =~ m/(?<=\@p\d{8}\t)[0-9A-Z]{6}/ && $Options{stickies} ne '0')
        {
          $SplitData =~ s/(?<=\@p\d{8}\t)[0-9A-Z]{6}/$Options{stickies}/;
        }
        elsif ($SplitData =~ m{
          ^\@Ename=(.+?)\r
          email=(.+?)\r
          figure=(.+?)\r
          sex=(.)\r
          customData=(.*?)\r
          ph_tickets=(.+?)\r
          ph_figure=(.*?)\r
          birthday=(.+?)\r
          photo_film=(.+?)\r
          directMail=(.+?)$_1$
          }x ) {
          $MyName = $1;
          $Persona{$MyName}->{Name} = $1;
          $Persona{$MyName}->{Email} = $2;
          $Persona{$MyName}->{Figure} = $3;
          $Persona{$MyName}->{Sex} = $4;
          $Persona{$MyName}->{CustomData} = $5 || 'undef';
          $Persona{$MyName}->{PoolTickets} = $6;
          $Persona{$MyName}->{PoolFigure} = $7 || 'null';
          $Persona{$MyName}->{Birthday} = $8;
          $Persona{$MyName}->{PhotoFilm} = $9;
          $Persona{$MyName}->{DirectMail} = $10;
        }
        
        elsif ($SplitData =~ m/^\@alogin incorrect:/) {
          Message('Login incorrect');
          Message('Restarting');
          foreach my $sock ($Library->handles)
          {
            close $sock;
            $Library->remove($sock);
          }
          sleep 3;
          $proc->Kill(0);
          exec($0);
        }
        elsif ($SplitData =~ m/^\@B(fuse.+)$_1$/)
        {
          $Data{fuse_rights} = $1;
        }

        if ($Options{trade} == 1)
        {
          $SplitData =~ s/(?<=$_2[HI])[HI](?=[HI]$_1)/I/g;
        }

        while ($AntiError == 1 && $SplitData =~ m<bottle.+DIR/([^0123456])>)
        {
          my $oldDirection = $1;
          $SplitData =~ s|bottle(.+?)DIR/[^0123456]|bottle$1DIR/6|xg;
          Notice('Error Notifier:'."\r\r".'Nullified corrupt bottle with invalid direction '.$oldDirection.'.');
        }

        if ($AntiError == 1 && $SplitData =~ m/Al.+$_30 photo $_30 .+ bobba/x)
        {
          my ($name, $victim) = ($1, $2) if ($SplitData =~ m/^Al(.+?)\t.+\r(.+?)\s+/);
          if ($name ne $MyName)
          {
            $SplitData = 'BKError Notifier:'."\r\r".
                         'Habbo '.$name.' tried to error you! '.
                         'What an asshole ';
            if (exists $Persona{$name})
            {
              $SplitData .= ($Persona{$name}->{Sex} eq 'm' ? 'he' : 'she');
            }
            else {
              $SplitData .= 'that';
            }
            $SplitData .= ' is!'."\r".$_1;
          }
          else {
            $SplitData = 'BKSuccessfully sent error photo to '.$victim."\r".$_1;
          }
        }
        
        for (my $i=0;$i<@Filters;$i++)
        {
          if (exists $Filters[$i] && $Filters[$i]->{Enabled} == 1)
          {
            $SplitData =~ s/$Filters[$i]->{Search}/$Filters[$i]->{Replacement}/g;
          }
        }

        print $SckClient $SplitData;

        ++$Counters{clientpackets};
        $Counters{clientbytes} += length($SplitData);
        
        if ($Options{datalog} == 1)
        {
          mkdir 'log' unless (-d $DIR.'log');
          open DATALOG, ">>", $DIR.'log/datalog.log';
          print DATALOG '[Received]'."\n".$SplitData."\n\n";
          close DATALOG;
        }
      }
    }
    elsif ($Socket == $SckClient) {
      print $SckServer $Data;

      ++$Counters{serverpackets};
      $Counters{serverbytes} += length($Data);

      if ($Options{datalog} == 1)
      {
        mkdir 'log' unless (-d $DIR.'log');
        open DATALOG, ">>", $DIR.'log/datalog.log';
        print DATALOG '[Sent]'."\n".$Data."\n\n";
        close DATALOG;
      }
    }
  }
}

### DECLARE COMMON SUBROUTINES

sub Message
{
  my $message = shift;
  print colored['bold white'], "\n".($MyName ? $MyName : 'offline').'> ', colored['bold white'], $message."\n";
}

sub Input
{
  my $message = shift;
  my $input;
  print colored['bold white'], "\n".($MyName ? $MyName : 'offline').'> ';
  print color 'bold green';
  print $message if (defined $message);
  $input = <STDIN>;
  $input = ' ' if (!defined $input);
  chomp($input);
  return $input;
  print color 'reset';
}

sub GetHabboID
{
  use IO::Socket;
  my ($Hotel, $Language) = (+shift, 'en');
  my ($ID, @HtmlSource);
  while (!defined $ID)
  {
    my $Socket = IO::Socket::INET->new
        (
            PeerAddr	=>	$Hotel,
            PeerPort	=>	'80',
            Proto	=>	'tcp'
        ) or die 'Can\'t create socket: '.$!;
    print $Socket 'GET /habbo/'.$Language.' HTTP/1.0'."\r\n\r\n";
    @HtmlSource = <$Socket>;
    close $Socket;
    for ( @HtmlSource ) {
      if ( m/\?t=(\d{13})/ ) {
          $ID = $1;
          last;
      }
    }
    $Language = $1 if (!defined $ID && $Hotel =~ m/^.+\.(.+)$/);
  }
  return ($ID, $Language);
}

sub MakeTmpHabbo
{
  use IO::Socket;
  my ( $Hotel, $Language, $ID ) = @_;
  my $Socket = IO::Socket::INET->new
      (
          PeerAddr	=>	$Hotel,
          PeerPort	=>	'80',
          Proto		=>	'tcp'
      ) or die 'Can\'t create socket: '.$!;
  print $Socket 'GET /habbo/'.$Language.'/common/habbo_client/client_popup/?t='.$ID.' HTTP/1.0'."\r\n\r\n";
  my @HtmlSource = <$Socket>;
  close $Socket;
  shift @HtmlSource while ( $HtmlSource[0] !~ m/^</ );
  my $StrippedSource = join( '', @HtmlSource );
  $StrippedSource =~ s/\n+/\n/g;
  my $Server = $1 if ( $StrippedSource =~ m/connection.info.host=(.+)(?=\")/ );
  $StrippedSource =~ s/(?<=connection.info.host=)(?:.+)(?=\")/127.0.0.1/g;
  my $Port = $1+1 if ( $StrippedSource =~ m/connection.info.port=(.+)(?=\")/ );
  $StrippedSource =~ s/(?<=connection.info.port=)(?:.+)(?=\")/$Port/g;
  mkdir 'tmp' unless -d( $DIR.'tmp' );
  open HTML, ">", $DIR.'tmp/tmp.html';
  print HTML $StrippedSource;
  close HTML;
  return( $Server, $Port-1, $Port );
}

sub LaunchBrowser
{
  Win32::Process::Create($proc,
                         $DIR.'LD.exe',
                         '',
                         0,
                         DETACHED_PROCESS,
                         $DIR
                        );
}

sub DecodeHabboID
{
  my $Code = shift;
  if    ($Code eq 'H') { return 0; }
  elsif ($Code eq 'I') { return 1; }
  elsif ($Code eq 'J') { return 2; }
  elsif ($Code eq 'K') { return 3; }
  else {
    my $Hash = {
      P	=>	0,
      Q	=>	1,
      R	=>	2,
      S	=>	3,
    };
    my ($First, $Second) = split(//, $Code);
    my $Start = int((ord($Second)-65)*4+4);
    return($Start+$Hash->{$First});
  }
}

sub EncodeHabboID
{
  my $ID = shift;
  if    ($ID == 0) { return 'H'; }
  elsif ($ID == 1) { return 'I'; }
  elsif ($ID == 2) { return 'J'; }
  elsif ($ID == 3) { return 'K'; }
  else {
    my @Array = ('P', 'Q', 'R', 'S');
    my ($Start, $Extra) = ($ID, 0);
    while (($Start / 4) =~ m/\./) {
      $Start -= 1;
      $Extra += 1;
    }
    return($Array[$Extra].chr($Start/4+64));
  }
}

sub Notice
{
  my $msg = shift;
  $msg .= "\r" if ($msg !~ m/\r$/);
  while ($msg =~ s/^((?:.*?\r){30})//)
  {
    SendToClient('BK'.$1.$_1);
  }
  SendToClient('BK'.$msg.$_1);
  $msg = '';
}

sub Error
{
  my $msg = shift;
  Notice('Scriptwise error:'."\r\r".$msg);
  $msg = '';
}

sub SendToClient
{
  my $data = shift;
  $data = $_1 if (!$data);

  mkdir 'log' unless (-d $DIR.'log');
  open DATALOG, ">>", $DIR.'log/datalog.log';
  print DATALOG '[Received]'."\n".$data."\n\n";
  close DATALOG;

  print $SckClient $data;
  $Counters{clientbytes} += length($data);
  $data = '';
  ++$Counters{clientpackets}
}

sub SaveChat
{
  my $msg = shift;
  $msg =~ s/^\s+//g;
  $msg =~ s/\s+$//g;
  $msg =~ s/[\r\n]+//g;
  my $time = localtime();
  unless (-d $DIR.'log') { mkdir $DIR.'log' || warn "\n".'# Can\'t create .\log directory: '.$!; }
  open CHATLOG, ">>", $DIR.'log/chatlog.log' || warn "\n".'# Can\'t open chatlog: '.$!;
  print CHATLOG "\n".'['.$time.']'."\n".$msg."\n";
  close CHATLOG;
}

### DECLARE COMMAND SUBROUTINES

sub Get_users
{
  my $var = 'Room/User IDs:'."\r\r";
  $var .= join("\r", map { $_."\t".'=='."\t".$IDs{$_} } 
    sort {$a<=>$b} keys %IDs );
  Notice($var);
  $var = '';
}

sub Get_info
{
  my $user = shift;
  if (!$user || !exists $Persona{$user})
  {
    Error('The name you specified was not found in the room!'."\r".
          'Use the \':get_users\' command to get a list of habbos.');
  }
  else {
    my $ref = $Persona{$user};
    my ($total, $current);
    foreach (sort
            {
              length($ref->{$a}) < length($ref->{$b}) ? -1 : 1;
            }
            keys %$ref)
    {
      $current = $_;
      $current .= ' ' while (length($current) < 12);
      $total .= $current."\t".'=='."\t".$ref->{$_}."\r";
    }
    Notice($total);
  }
}

sub Set_mission
{
  my $mission = shift;
  if (!defined $mission)
  {
    Error('You forgot to specify a mission!');
  }
  else {
    SendToClient(
      '@Ename='.$Persona{$MyName}->{Name}."\r".
      'email='.$Persona{$MyName}->{Email}."\r".
      'figure='.$Persona{$MyName}->{Figure}."\r".
      'sex='.$Persona{$MyName}->{Sex}."\r".
      'customData='.$mission."\r".
      'ph_tickets='.$Persona{$MyName}->{PoolTickets}."\r".
      'ph_figure='.$Persona{$MyName}->{PoolFigure}."\r".
      'birthday='.$Persona{$MyName}->{Birthday}."\r".
      'photo_film='.$Persona{$MyName}->{PhotoFilm}."\r".
      'directMail='.$Persona{$MyName}->{DirectMail}.$_1
    );
    Notice('Mission is set. Update your ID and edit it slightly.');
  }
}

sub Get_vars
{
  my $var = 'User set variables:'."\r\r";
  for (my $i = 0; $i < scalar(@Vars)+1; $i++)
  {
    $var .= $i."\t".'=='."\t".$Vars[$i]."\r" if (exists $Vars[$i]);
  }
  Notice($var);
}

sub Set_var
{
  my ($number, $var) = @_;
  if (!defined $number || $number !~ m/^\d+$/ || $number > 30)
  {
    Error('The number you specified is invalid or is not even a number!'."\r".
          'Please note, the maximum number of variables is 30 to save resources.');
  }
  else {
    $Vars[$number] = $var;
    Notice('Successfully set var_'.$number.' to \''.$var.'\'.');
  }
}

sub App_var
{
  my ($number, $var) = @_;
  if (!defined $number || $number !~ m/^\d+$/ || $number > 30 || !exists $Vars[$number])
  {
    Error('The number you specified is invalid or is not even a number!'."\r".
          'Please note, the maximum number of variables is 30 to save resources.');
  }
  else {
    $Vars[$number] .= $var;
    Notice('Successfully appended \'$var\' to var_'.$number.'.');
  }
}

sub Rem_var
{
  my $number = shift;
  if (!defined $number || $number !~ m/^\d+$/ || $number > 30 || !exists $Vars[$number])
  {
    Error('The number you specified is invalid or is not even a number!'."\r".
          'Please note, the maximum number of variables is 30 to save resources.');
  }
  else {
    delete $Vars[$number];
    Notice('Successfully removed var_'.$number.'.');
  }
}

sub Get_filters
{
  my $var = 'User set filters:'."\r\r";
  for (my $i=0;$i<@Filters;$i++)
  {
    if (exists $Filters[$i])
    {
      $var .= $i.' '.
              ($Filters[$i]->{Enabled} == 0 ? '(Off)' : '(On)').
              "\t".'=='."\t".$Filters[$i]->{Name}."\r";
    }
  }
  Notice($var);
}

sub Set_filter
{
  if (!@_ || (@_) < 4)
  {
    Error('Proper syntax:'."\r".
          ':set_filter <filterID>, <name>, <search>, <replacement>'."\r\r".
          'Example:'."\r".
          ':set_filter 1, mocha2dew, mocchamaster, md_limukaapi');
  }
  else {
    my ($number, $name, $search, $replacement) = @_;
    if ($number !~ m/^\d+$/)
    {
      Error('Your filterID is not a digit!');
    }
    else {
      $Filters[$number]->{Name} = $name;
      $Filters[$number]->{Search} = $search;
      $Filters[$number]->{Replacement} = $replacement;
      $Filters[$number]->{Enabled} = 0;
      Notice('Successfully set filter '.$number.' to \''.$name.'\'');
    }
  }
}

sub Rem_filter
{
  my $var = 'Filter Removing:'."\r\r";
  foreach my $number (sort {$a <=> $b} @_)
  {
    if (defined $number && $number =~ m/^[0-9]+$/ && exists $Filters[$number])
    {
      delete $Filters[$number];
      $var .= 'Filter '.$number."\t".'=='."\t".'removed.'."\r";
    }
  }
  Notice($var);
}

sub Toggle_filter
{
  my $var = 'Filter Toggling:'."\r\r";
  foreach my $number (sort {$a <=> $b} @_)
  {
    if (defined $number && $number =~ m/^[0-9]+$/ && exists $Filters[$number])
    {
      $Filters[$number]->{Enabled} = ($Filters[$number]->{Enabled} == 0 ? 1 : 0);
      $var .= 'Filter '.$number.' '."\t".'=='."\t".($Filters[$number]->{Enabled} == 0 ? 'disabled' : 'enabled').".\r";
    }
  }
  Notice($var);
}

sub Load_filter
{
  my $file = (+shift).'.hsf';
  if ($file && open FILTER, $DIR.'flt/'.$file)
  {
    @Filters = ();
    my ($data, $hex, $err);
    my ($i, $line) = 0;
    while (<FILTER>)
    {
      ++$line;
      if (m/^#/ || m/^\s+$/)
      {
        next;
      }
      else {
        $data = $_;
        if    ($data =~ m/^I:(\d+)$/)
        {
          $i = $1;
          $Filters[$i]->{Enabled} = 0;
        }
        elsif ($data =~ m/^N:(.+)$/) {
          $Filters[$i]->{Name} = $1;
        }
        elsif ($data =~ m/^S:(.+)$/) {
          $hex = $1;
          $hex =~ s/[^\s0-9A-Fa-f]+//g;
          foreach (split(/\s+/, $hex))
          {
            $_ = '0'.$_ while length($_) < 2;
            $Filters[$i]->{Search} .= pack("H*", $_);
          }
        }
        elsif ($data =~ m/^R:(.+)$/) {
          $hex = $1;
          $hex =~ s/[^\s0-9A-Fa-f]+//g;
          foreach (split(/\s+/, $hex))
          {
            $Filters[$i]->{Replacement} .= pack("H*", $_);
          }
        }
        else {
          $err .= 'Syntax error at ./flt/'.$file.', line '.$line.'!'."\r";
        }
      }
    }
    close FILTER;
    Notice('Successfully loaded filter \''.$file.'\'.');
    Error($err) if (defined $err);
  }
  else {
    Error('The filter you specified does not exist!');
  }
}

sub Save_filter
{
  if (@_ < 2)
  {
    Error('You didn\'t pass enough arguments!');
  }
  else {
    my ($name, $author, $comment) = @_;
    my $date = localtime();
    mkdir 'flt' unless (-d $DIR.'flt');
    if (open SAVFILTER, ">", $DIR.'flt/'.$name.'.hsf')
    {
      print SAVFILTER '# Habbo Scripting Filter'."\n";
      print SAVFILTER '# Created with Scriptwise'."\n\n";
      print SAVFILTER '# Name: '.$name."\n".
                      '# Auth: '.$author."\n";
      print SAVFILTER '# Comm: '.$comment."\n" if (defined $comment);
      print SAVFILTER '# Date: '.$date;
      for (my $i=0;$i<@Filters;$i++)
      {
        if (exists $Filters[$i])
        {
          print SAVFILTER "\n";
          print SAVFILTER "\n".'I:'.$i;
          print SAVFILTER "\n".'N:'.$Filters[$i]->{Name};
          print SAVFILTER "\n".'S:',join(' ', map { uc(unpack("H*", $_)); }
            split('', $Filters[$i]->{Search}));
          print SAVFILTER "\n".'R:',join(' ',map { uc(unpack("H*", $_)); }
            split('', $Filters[$i]->{Replacement}));
        }
      }
      close SAVFILTER;
      Notice('Successfully saved filter \''.$name.'.hsf\'.');
    }
    else {
      Error('Can\'t open file \''.$name.'.hsf\' for output!'."\r".$!);
    }
  }
}

sub Text2hex
{
  my $var = shift;
  my $code;
  $code .= sprintf("%x ", ord($_)) foreach (split("", $var));
  Notice('Text2hex converter:'."\r\r".'[TEXT]'."\r".$var."\r\r".'[HEX]'."\r".uc($code));
}

sub Receive
{
  SendToClient(@_);
}

sub Make_talk
{
  my ($user, $msg) = @_;
  if (!defined $user || !defined $msg || !exists $Persona{$user})
  {
    Error('Either the user does not exist or you forgot to specify a message!');
  }
  else {
    SendToClient('@Z'.EncodeHabboID($Persona{$user}->{ID}).$msg.$_2.$_1);
  }
}

sub Mass_talk
{
  my $var = shift;
  if (!defined $var)
  {
    Error('You forgot to specify a message!');
  }
  else {
    my $total = '';
    foreach (keys %IDs)
    {
      $total .= '@Z'.EncodeHabboID($_).$var.$_2.$_1;
    }
    SendToClient($total);
  }
}
sub Mass_task
{
  Notice('Hit enter on the terminal to disable mass task and '.
         'to return to normal data flow.');
  Message('Hit enter to disable mass task');
  Input();
  Message('Mass task disabled');
}

sub Toggle_datalog
{
  $Options{datalog} = ($Options{datalog} == 1 ? 0 : 1);
  Notice('Datalogging has now been '.
        ($Options{datalog} == 1 ? 'enabled.' : 'disabled.'));
}

sub Get_datalog
{
  system 'explorer .\log\datalog.log';
}

sub Rem_datalog
{
  if (unlink $DIR.'log/datalog.log')
  {
    Notice('Successfully removed the data logfile.');
  }
  else {
    Error('The data logfile has already been removed!');
  }
}

sub Toggle_chatlog
{
  $Options{chatlog} = ($Options{chatlog} == 1 ? 0 : 1);
  Notice('Chatlogging has now been '.
        ($Options{chatlog} == 1 ? 'enabled.' : 'disabled.'));
  SaveChat('*** Scriptwise chatlog '.
          ($Options{chatlog} == 1 ? 'enabled' : 'disabled').
           ' ***' );
}

sub Get_chatlog
{
  my $path = $0;
  $path =~ s/\\[^\\]+$/\\/;
  system 'explorer '.$path.'log\chatlog.log';
}

sub Rem_chatlog
{
  if (unlink $DIR.'log/chatlog.log')
  {
    Notice('Successfully removed the chat logfile.');
  }
  else {
    Error('The chat logfile has already been removed!');
  }
}

sub Set_credits
{
  my $credits = shift;
  if (!$credits || $credits !~ m/^[-+]?[0-9]+$/ || $credits > 9999)
  {
    Error('You specified an invalid number!'."\r".
          'The maximum amount of credits is 9999.');
  }
  else {
    SendToClient('@F'.$credits.'.0'.$_1);
  }
}

sub Set_scolor
{
  my $color = shift;
  $color = uc($color);
  if (!defined $color || $color !~ m/^[A-Z0-9]{6}$/)
  {
    $Options{stickies} = 0;
    Notice('Stickies are no longer edited.');
  }
  else {
    $Options{stickies} = $color;
    Notice('Stickies will now be edited.');
  }
}

sub Toggle_hc
{
  $Options{habbo_club} = $Options{habbo_club} == 1 ? 0 : 1;
  if ($Options{habbo_club} == 1)
  {
    SendToClient('@Bfuse_use_special_room_layouts'."$_2".
                 'fuse_buy_credits'.$_2.
                 'fuse_login'.$_2.
                 'fuse_furni_chooser'.$_2.
                 'fuse_priority_access'.$_2.
                 'fuse_use_club_outfits'.$_2.
                 'default'.$_2.
                 'fuse_use_club_badge'.$_2.
                 'fuse_trade'.$_2.
                 'fuse_habbo_chooser'.$_2.
                 $_1);
    Notice('You can now use :chooser, :furni and create special rooms.');
  }
  else {
    SendToClient('@B'.$Data{fuse_rights}.$_1);
    Notice('Your original settings have been restored.');
  }
}

sub Toggle_trade
{
  $Options{trade} = $Options{trade} == 0 ? 1 : 0;
  if ($Options{trade} == 1)
  {
    Notice('You can now trade with anyone in all guest rooms.'."\r".
           'Reload the current room for the effects to take place.');
  }
  else {
    Notice('You can now only trade in the specific trade rooms.'."\r".
           'Reload the current room for the effects to take place.');
  }
}

sub Anti_error
{
  if (!$AntiError || $AntiError == 0)
  {
    $AntiError = 1;
  }
  else {
    $AntiError = 0;
  }
  Notice('The error notifier has now been '.
  ($AntiError == 1 ? 'enabled.' : 'disabled.'));
}

sub Gimme_cam
{
  SendToClient('BLSI-103820520S10382052camera110,0,0/1');
}

sub Data
{
  my $var = 'Data:'."\r\r".
            'Packets to client'."\t".'=='."\t".$Counters{clientpackets}.' '.
            '('.$Counters{clientbytes}.' bytes)'."\r".
            'Packets to server'."\t".'=='."\t".$Counters{serverpackets}.' '.
            '('.$Counters{serverbytes}.' bytes)'."\r".
            'Converstations'."\t".'=='."\t".$Counters{conversations}.' ';
  Notice($var);
}

sub Cls
{
  system 'cls';
}

sub Restart
{
  $proc->Kill(0);
  exec($0);
}

sub Exit
{
  $proc->Kill(0);
}

sub Notes
{
  mkdir 'not' unless (-d $DIR.'not');
  system 'notepad .\not\notes.dat';
}

sub About
{
  my $var = "Scriptwise v1 (BETA 3).\r".
            "Created by Mitch in PERL.\r".
            "http://www.scriptwise.tk\r".
            "http://www.scriptwise.cjb.net\r\r".
            "Thanks to:\r".
            "Arikato, Milan, Paul (2x), Ed, John,\r".
            "Derrick, Callum, Kenneth, Neil,\r\r".
            "All BETA testers and users.";
  Notice($var);
}

sub END
{
  unlink $DIR.'tmp/tmp.html';
  rmdir $DIR.'tmp';
}