#!/usr/bin/perl
# Filename:	dAIve
# Author:	David Ljung Madison <DaveSource.com>
# See License:	http://MarginalHacks.com/License
# Description:	AI interface to dopewars
# Version:	1.01
use strict;
use IO::Socket;

##################################################
# Setup the variables
##################################################
my $PROGNAME	= $0;
$PROGNAME	=~ s|.*/||;

# Dopewars stuff
my $DW_VERSION	= "1.4.8";
my $MESSAGE_H	= "dopewars-$DW_VERSION/message.h";

# This is a guess - the server doesn't tell us that it's our last day  :(
my $NUM_TURNS	= 30;

# Dopewars server
my $HOST	= "localhost";
my $PORT	= 7902;

##################################################
# Allow override of any internal functions
# They can specify any perl code on the command line
##################################################
my @USING;
sub load_ai {
  (@USING) = @_;

  foreach my $ai ( @USING ) {
    next if ($ai eq "");
    if (-f $ai) {
      if (!do $ai) {
        print STDERR "[$0]  Couldn't read ai [$ai]:\n  $!\n" if ($!);
        print STDERR "[$0]  Couldn't compile ai [$ai]:\n  $@\n" if ($@);
      }
      print "Using AI module:  $ai\n";
    } else {
      print STDERR "[$0]  Couldn't find AI module [$ai]\n" if ($ai);
    }
  }
}
load_ai(@ARGV);

##################################################
# Connection
##################################################

# This is the hokey way to write a client, using telnet..
sub expect {
  my ($exp) = @_;
  die("Expected expression [$exp]\nSaw: $_\n")
    unless (/$exp/);
}

sub client {
  my ($host,$port) = @_;

  $host = $host || "localhost";
  $port = $port || 7902;

  my $handle = IO::Socket::INET->new(Proto    => "tcp",
                                     PeerAddr => $host, PeerPort => $port)
               or die "cannot connect to port [$port] at localhost";
  $handle->autoflush(1);

  $handle;
}

##################################################
# Game object (holds all game information)
# Utility functions
##################################################
sub list_drugs { my ($game) = @_;  @{$game->{'Drugs'}}; }
sub list_locations { my ($game) = @_;  @{$game->{'Locations'}}; }
sub location { my ($game) = @_;  $game->{'Inv'}{'IsAt'}; }
sub location_name { my ($game,$i) = @_;  $game->{'Locations'}[$i]; }
sub loan_shark {
  my ($game,$set) = @_;
  $game->{'Home'}{'LoanShark'} = $set if (defined $set);
  $game->{'Home'}{'LoanShark'};
}
sub list_players { my ($game) = @_;  @{$game->{'Players'}}; }
sub drug_name { my ($g,$i) = @_;  $g->{'Drugs'}[$i]{'Name'}; }
sub drug_price { my ($g,$i) = @_;  $g->{'Prices'}[$i]; }
sub drug_ave { my ($g,$i) = @_;  $g->{'Drugs'}[$i]{'Ave'}; }
sub drug_min { my ($g,$i) = @_;  $g->{'Drugs'}[$i]{'Min'}; }
sub drug_max { my ($g,$i) = @_;  $g->{'Drugs'}[$i]{'Max'}; }
sub turn_num { my ($g) = @_;  $g->{'Inv'}{'Turn'}; }
sub inv_debt { my ($g) = @_;  $g->{'Inv'}{'Debt'}; }
sub inv_cash { my ($g) = @_;  $g->{'Inv'}{'Cash'}; }
sub inv_drugs { my ($g) = @_;  @{$g->{'Inv'}{'Drugs'}}; }
sub inv_drug { my ($g,$i) = @_;  $g->{'Inv'}{'Drugs'}[$i]; }
sub spaces_avail {
  my ($game) = @_;
  my $spaces = $game->{'Inv'}{'CoatSize'};
  for (my $drug=0; $drug<$game->{'NumDrugs'}; $drug++) {
    $spaces -= inv_drug($game,$drug);
  }
  $spaces;
}

##################################################
##################################################
##################################################
# Make decisions
#   This is the 'AI' part of the code.  If you
#   want to write your own drugwars 'bot, then cut
#   out this section and make it a new perl program.
##################################################
##################################################
##################################################

# Choose our name
# This needs to return a different name each time it's
# called, in case someone is already using the name we try
sub ChooseName {
  my ($game) = @_;

  return ++$game->{'Name'} if ($game->{'Name'});

  $game->{'Name'} = $PROGNAME;
}

sub DealDrugs {
  my ($game) = @_;

  my $turns_left = $NUM_TURNS - turn_num($game);

  # Since there is no cost to buying back a drug we just sold, we
  # can simplify the logic for deciding which drugs to sell and then
  # buy by selling all drugs, and then trying to buy drugs sorted according
  # to which are the best buy.  If we sell a drug we shouldn't have, then
  # arguably we should buy it back, otherwise our sort algorithm is broken.

  # See what's available, sell all drugs, choose some to buy
  my @wanted;
  for (my $drug=0; $drug<$game->{'NumDrugs'}; $drug++) {
    # Not available here
    next unless (drug_price($game,$drug));

    # We want drugs that are cheap by more than some percent
    my $percent = 10;
    $percent = 20 if ($turns_left == 2);	# Careful!
    $percent = 40 if ($turns_left == 1);	# Careful!
    my $profit = drug_ave($game,$drug) - drug_price($game,$drug);
    push(@wanted,$drug) if ($profit > drug_price($game,$drug)*$percent/100);

    # Sell everything, wanted or not (you can't always get what you want :)
    SellDrug($game,$drug,inv_drug($game,$drug)) if (inv_drug($game,$drug));
  }

  if (@wanted && $turns_left) {

    # Sort algorithm for which drugs to buy
    sub best_buy {
      my $a_profit = drug_ave($game,$a) - drug_price($game,$a);
      my $b_profit = drug_ave($game,$a) - drug_price($game,$a);
      $b_profit <=> $a_profit;
    }

    # Buy the more expensive drugs first to conserve space/$
    foreach my $drug ( sort best_buy @wanted ) {
      BuyDrug($game,$drug,undef);	# Buy all we can
    }
  }

  # Did we miss out on selling some drugs?
  if (!$turns_left) {
    for (my $drug=0; $drug<$game->{'NumDrugs'}; $drug++) {
      print "Damn:  Didn't sell ",inv_drug($game,$drug),
            " of ",drug_name($game,$drug)," (losing approx \$",
            (inv_drug($game,$drug)*drug_ave($game,$drug)),")\n"
        if (!drug_price($game,$drug) && inv_drug($game,$drug));
    }
  }
}

sub JetTo {
  my ($game) = @_;

  my $loc = location($game);

  # Time to see the loan shark?
  my $debt = inv_debt($game);
  my $shark = loan_shark($game);
  return $shark
    if (defined($shark) && $loc != $shark &&
        $debt && inv_cash($game)*1.2 > $debt);

  ($loc+1) % $#{$game->{'Locations'}};
}

# Amount to pay the loan shark
sub Pay_LoanShark {
  my ($game) = @_;

  my $debt = inv_debt($game);

  # As long as we have enough left over, pay the loan shark!
  return $debt if (inv_cash($game)*1.1 > $debt);
  return 0;
}

##################################################
##################################################
##################################################
# End decision section
##################################################
##################################################
##################################################

##################################################
# Communication to server
##################################################

#   SendClientMessage(NULL,C_NONE,C_NAME,NULL,AIPlay->Name);
#SendClientMessage(PLAYER *From,char AICode,char Code,PLAYER *To,char *Data)
#sprintf(text,"%s^%s^%game->{'C'}%s",From->Name, To->Name,AICode,Code,Data);
#from^to^codecodedata

sub SendClientMessage {
  my ($game,$From,$AICode,$Code,$To,$Data) = @_;
  my $code = $game->{'C'}{$Code} || $game->{'DT'}{$Code};
  print "[$PROGNAME] Unknown Code: $Code\n" unless $code;
  my $aicode = $game->{'C'}{$AICode};
  print "[$PROGNAME] Unknown AICode: $AICode\n" unless $aicode;
  #printf(STDERR "Send: %s^%s^%s%s%s\n",$From || "",$To || "",$aicode,$code,$Data);
  my $h = $game->{'handle'};
  printf($h "%s^%s^%s%s%s\n",$From || "",$To || "",$aicode,$code,$Data);
}

sub SetName {
  my ($game) = @_;
  SendClientMessage($game,0,'NONE','NAME',0,$game->{'Name'});
}

sub SellDrug {
  my ($game,$num,$amt) = @_;
  BuyDrug($game,$num,-$amt);
}

# Use undefined $amt to buy as much as possible
sub BuyDrug {
  my ($game,$drug,$amt) = @_;

  if (!defined $amt || $amt>0) {
    # Buying
    my $can_afford = int($game->{'Inv'}{'Cash'} / drug_price($game,$drug));
    my $spaces_avail = spaces_avail($game);

    $amt = $can_afford if (!defined $amt || $amt > $can_afford);
    $amt = $spaces_avail if (!defined $amt || $amt > $spaces_avail);
    return unless $amt;
#print "Buy $amt x ",drug_name($game,$drug)," at ",drug_price($game,$drug),"\n";
  } else {
    # Selling (amount is negative!)
    my $inventory = inv_drug($game,$drug);

    $amt = -$inventory if ($amt < -$inventory);
    return unless $amt;
#print "Sell ",-$amt," x ",drug_name($game,$drug)," at ",drug_price($game,$drug),"\n";
  }

  SendClientMessage($game,$game->{'Name'},'NONE','BUYOBJECT',0,"drug^$drug^$amt");

# Could just get the UPDATE message that we should be seeing..
  # Adjust cash
  $game->{'Inv'}{'Cash'} -= $amt * drug_price($game,$drug);

  # Adjust drug inventory
  $game->{'Inv'}{'Drugs'}[$drug] += $amt;
}

sub Jet {
  my ($game) = @_;

  my $to = JetTo($game);
  #print "Jet to [$to]: $game->{'Locations'}[$to]\n";
  SendClientMessage($game,$game->{'Name'},'NONE','REQUESTJET',0,$to);
}

##################################################
# Handle information from server
##################################################
sub get_message {
  my ($game) = @_;

  # Read some input, break up the fields
  my $h = $game->{'handle'};
  return undef unless ($_ = <$h>);
  chomp;
  return get_message($game) if (/^\s*$/);

  unless (/^([^\^]*)\^([^\^]*)\^(.)(.)(.*)$/) {
    print "[$PROGNAME] Bad network message. Oops:\n  [$_]\n";
    next;
  }

  return ($1,$2,$3,$4,$5);
}

# Regular expressions for the Data field
my $WORD	= '([^\^]+)';
my $NUM 	= '(\d+)';
my $Br		= '\^';
my $WORDb	= $WORD.$Br;
my $NUMb	= $NUM.$Br;

sub game_loop {
  my ($game) = @_;

  SetName($game,ChooseName($game));

  # Handle messages
  while (1) {
    my ($From,$To,$AICode,$Code,$Data) = get_message($game);
    last unless defined $From;

    #print "Got [$_]\n";
    #print "From: $From\nTo: $To\nCodes: $AICode,$Code\nData: $Data\n";

    # Decode the message

    #########################
    # INIT
    #########################
    if ($Code eq $game->{'C'}{'INIT'}) {
      # Init message:
      # "%s^%d^%d^%d^%s^%s^%s^%s^%s^%s^%s^%s^",
      #   VERSION,NumLocation,NumGun,NumDrug,
      #   Names.Bitch,Names.Bitches,Names.Gun,Names.Guns,
      #   Names.Drug,Names.Drugs,Names.Month,Names.Year);
      die("[$PROGNAME] Couldn't understand INIT message:\n  [$Data]\n")
        unless ($Data =~ /^$WORDb$NUMb$NUMb$NUMb$WORDb$WORDb$WORDb$WORDb$WORDb$WORDb$WORDb$WORDb$/);
      ($game->{'Version'},$game->{'NumLocs'},$game->{'NumGuns'},$game->{'NumDrugs'},
       $game->{'Names'}{'Bitch'}, $game->{'Names'}{'Bitches'},
       $game->{'Names'}{'Gun'}, $game->{'Names'}{'Guns'},
       $game->{'Names'}{'Drug'}, $game->{'Names'}{'Drugs'},
       $game->{'Names'}{'Month'}, $game->{'Names'}{'Year'}) =
        ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12);
      print STDERR "Server version [$game->{'Version'}] does not match [$DW_VERSION]\n"
        if ($game->{'Version'} ne $DW_VERSION);

    #########################
    # Our name is taken
    #########################
    } elsif ($Code eq $game->{'C'}{'NEWNAME'}) {
      # We need to pick a new name
      SetName($game,ChooseName($game));

    #########################
    # Someone joined/left the game, list players
    #########################
    } elsif ($Code eq $game->{'C'}{'JOIN'}) {
      print "[$PROGNAME] \"$Data\" joined the game\n";
      $game->{'Players'}{$Data} = 1;
    } elsif ($Code eq $game->{'C'}{'LEAVE'}) {
      print "[$PROGNAME] \"$Data\" left the game\n";
      undef $game->{'Players'}{$Data};
    } elsif ($Code eq $game->{'C'}{'LIST'}) {
      print "[$PROGNAME] Player in game:  $Data\n";
      $game->{'Players'}{$Data} = 1;

    #########################
    # DATA
    #########################
    } elsif ($Code eq $game->{'C'}{'DATA'}) {
      # Data is either prices, locations, guns or drugs
      # "num^Dstr^str^..
      die("[$PROGNAME] Couldn't understand DATA message:\n  [$Data]\n")
        unless ($Data =~ /^$NUMb(.)(.+)/);
      my ($num,$dt,$str) = ($1,$2,$3);

      #########################
      # DATA, DT_PRICES
      if ($dt eq $game->{'DT'}{'PRICES'}) {
        # str is Prices.Spy, Prices.Tipoff
        print STDERR "[$PROGNAME] DT_PRICES error [$Data]\n"
          unless ($str =~ /^$NUMb$NUMb$/);
        $game->{'Cost'}{'Spy'} = $1;
        $game->{'Cost'}{'Tipoff'} = $2;

      #########################
      # DATA, DT_LOCATION
      } elsif ($dt eq $game->{'DT'}{'LOCATION'}) {
        $str =~ s/\^$//;
        $game->{'Locations'}[$num] = $str;

      #########################
      # DATA, DT_DRUG
      } elsif ($dt eq $game->{'DT'}{'DRUG'}) {
        print STDERR "[$PROGNAME] DT_DRUG error [$Data]\n"
          unless ($str =~ /^$WORDb$NUMb$NUMb$/);
        $game->{'Drugs'}[$num]{'Name'} = $1;
        $game->{'Drugs'}[$num]{'Min'} = $2;
        $game->{'Drugs'}[$num]{'Max'} = $3;
        $game->{'Drugs'}[$num]{'Ave'} = $2+($3-$2)/2;

      #########################
      # DATA, DT_GUN
      } elsif ($dt eq $game->{'DT'}{'GUN'}) {
        print STDERR "[$PROGNAME] DT_GUN error [$Data]\n"
          unless ($str =~ /^$WORDb$NUMb$NUMb$NUMb$/);
        $game->{'Guns'}{$1}{'num'} = $num;
        $game->{'Guns'}{$1}{'price'} = $2;
        $game->{'Guns'}{$1}{'space'} = $3;
        $game->{'Guns'}{$1}{'damage'} = $4;

      } else {
        print STDERR "[$PROGNAME] Unknown DT Type error [$dt,$Data]\n";
      }

    #########################
    # ENDLIST
    #########################
    } elsif ($Code eq $game->{'C'}{'ENDLIST'}) {
      print STDERR "[$PROGNAME] What do I do with C_ENDLIST??  [$Data]\n" if ($Data);
      # Otherwise ignore, we are stateless

    #########################
    # UPDATE  (Spy report or personal update)
    #########################
    } elsif ($Code eq $game->{'C'}{'UPDATE'}) {
      my $re = $NUMb x 8 . '(.+)';
      print STDERR "[$PROGNAME] UPDATE error [$Data]\n" unless ($Data =~ /^$re$/);
      if ($To eq $game->{'Name'}) {
        ($game->{'Inv'}{'Cash'}, $game->{'Inv'}{'Debt'}, $game->{'Inv'}{'Bank'}, $game->{'Inv'}{'Health'},
         $game->{'Inv'}{'CoatSize'}, $game->{'Inv'}{'IsAt'}, $game->{'Inv'}{'Turn'}, $game->{'Inv'}{'Flags'}) =
           ($1,$2,$3,$4,$5,$6,$7,$8);
        my @inv = split($Br,$9);
        @{$game->{'Inv'}{'Bitches'}} = pop(@inv);
        @{$game->{'Inv'}{'Guns'}} = splice(@inv,0,$game->{'NumGuns'});
        @{$game->{'Inv'}{'Drugs'}} = @inv;
        print "Inv [$game->{'Inv'}{'Turn'}] $game->{'Inv'}{'Cash'}/$game->{'Inv'}{'Debt'}, @{$game->{'Inv'}{'Drugs'}}\n";
      } else {
        print STDERR "[$PROGNAME] UPDATE - Spying on $To??\n";
      }

    #########################
    # Print Message
    #########################
    } elsif ($Code eq $game->{'C'}{'PRINTMESSAGE'}) {
# Ignore for now.
next;
      my @m = split($Br,$Data);
      print "Msg: ",join("\nMsg: ",@m),"\n";

    #########################
    # Y/N Question
    #########################
    } elsif ($Code eq $game->{'C'}{'QUESTION'}) {
      print STDERR "[$PROGNAME] QUESTION error [$Data]\n"
        unless ($Data =~ /^$WORDb(.+)$/);
      my ($type,$question) = ($1,$2);

      my $answer;

      # The AICode tells us what the question is:
         if ($AICode eq $game->{'C'}{'NONE'})		{ $answer = "N"; }	# Bad weed!
      elsif ($AICode eq $game->{'C'}{'ASKLOAN'})	{
        loan_shark($game,location($game));	# Set the loan shark location
        $answer = "Y";
      }
      elsif ($AICode eq $game->{'C'}{'COPS'})		{ $answer = "N"; }
      elsif ($AICode eq $game->{'C'}{'ASKBITCH'})	{ $answer = "N"; }
      elsif ($AICode eq $game->{'C'}{'ASKGUN'})		{ $answer = "N"; }
      elsif ($AICode eq $game->{'C'}{'ASKGUNSHOP'})	{ $answer = "N"; }
      elsif ($AICode eq $game->{'C'}{'ASKPUB'})		{ $answer = "N"; }
      elsif ($AICode eq $game->{'C'}{'ASKBANK'})	{ $answer = "N"; }
      elsif ($AICode eq $game->{'C'}{'ASKRUN'})		{ $answer = "Y"; }
      elsif ($AICode eq $game->{'C'}{'ASKRUNFIGHT'})	{ $answer = "R"; }
      elsif ($AICode eq $game->{'C'}{'ASKSEW'})		{ $answer = "N"; }
      elsif ($AICode eq $game->{'C'}{'MEETPLAYER'})	{ $answer = "E"; }	# Evade
      else { print STDERR "[$PROGNAME] Unknown QUESTION AICode: $AICode\n  [$type] $question\n"; }

      print STDERR "[$PROGNAME] Bad response: $answer\n  [$type] $question\n"
        if ($type !~ /$answer/);

      SendClientMessage($game,$game->{'Name'},'NONE','ANSWER',$From,$answer);

    #########################
    # Subway flash?
    #########################
    } elsif ($Code eq $game->{'C'}{'SUBWAYFLASH'}) {
next;
# Ignore for now.
      next unless $Data;
      my @m = split($Br,$Data);
      print "Subway: ",join("\nSubway: ",@m),"\n";

    #########################
    # Loan shark?
    #########################
    } elsif ($Code eq $game->{'C'}{'LOANSHARK'}) {
      my $pay = Pay_LoanShark($game);
      SendClientMessage($game,$game->{'Name'},'NONE','PAYLOAN',0,$pay) if ($pay);
      SendClientMessage($game,$game->{'Name'},'NONE','DONE',0,0)

    #########################
    # Drug prices
    #########################
    } elsif ($Code eq $game->{'C'}{'DRUGHERE'}) {
      @{$game->{'Prices'}} = split(/$Br/,$Data);
      print STDERR "[$PROGNAME] Wrong number of drugs? [$game->{'NumDrugs'}] [$Data]\n"
        unless ($#{$game->{'Prices'}}+1 == $game->{'NumDrugs'});

      #########################
      # Now we can deal some drugs!
      #########################
      DealDrugs($game);

      #########################
      # Where to now?
      #########################
      Jet($game);


    #########################
    # Start Hi Score (game over)
    #########################
    } elsif ($Code eq $game->{'C'}{'STARTHISCORE'}) {
      print STDERR "[$PROGNAME] STARTHISCORE Error? [$Data]\n" if ($Data);
      print STDERR "[$PROGNAME] Game Over\n";
      # Ignore - we are stateless

    #########################
    # Hi Score entry
    #########################
    } elsif ($Code eq $game->{'C'}{'HISCORE'}) {
      print STDERR "[$PROGNAME] HISCORE Error? [$Data]\n"
        unless ($Data =~ /^$NUMb([BN])(.+)$/);
      my ($num,$bold,$str) = ($1,$2 eq "B" ? 1 : 0, $3);
      $str =~ s/^[\s>]+//; $str =~ s/[\s<]+$//;
      printf "%s %-3d $str\n",($bold ? "->" : "  "),$num;

    #########################
    # End Hi Score
    #########################
    } elsif ($Code eq $game->{'C'}{'ENDHISCORE'}) {
      print STDERR "[$PROGNAME] ENDHISCORE Error? [$Data]\n"
        unless ($Data eq "end");
      # Ignore - we are stateless

    #########################
    # ??
    #########################
    } else {
      print STDERR "[$PROGNAME] Unknown code: [$Code,$Data]\n";
exit;
    }
  }
}

sub close_client {
  my ($game) = @_;
  close ($game->{'handle'})            || die "close: $!";
}

##################################################
# Get info from message.h
##################################################
sub default_message {
  my ($game) = @_;

  print STDERR "[$PROGNAME] Couldn't read message.h, using default values\n";
  $game->{'C'}{'PRINTMESSAGE'} = 'A';
  $game->{'C'}{'LIST'} = 'B';
  $game->{'C'}{'ENDLIST'} = 'C';
  $game->{'C'}{'NEWNAME'} = 'D';
  $game->{'C'}{'MSG'} = 'E';
  $game->{'C'}{'MSGTO'} = 'F';
  $game->{'C'}{'JOIN'} = 'G';
  $game->{'C'}{'LEAVE'} = 'H';
  $game->{'C'}{'SUBWAYFLASH'} = 'I';
  $game->{'C'}{'UPDATE'} = 'J';
  $game->{'C'}{'DRUGHERE'} = 'K';
  $game->{'C'}{'GUNSHOP'} = 'L';
  $game->{'C'}{'LOANSHARK'} = 'M';
  $game->{'C'}{'BANK'} = 'N';
  $game->{'C'}{'QUESTION'} = 'O';
  $game->{'C'}{'HISCORE'} = 'Q';
  $game->{'C'}{'STARTHISCORE'} = 'R';
  $game->{'C'}{'ENDHISCORE'} = 'S';
  $game->{'C'}{'BUYOBJECT'} = 'T';
  $game->{'C'}{'DONE'} = 'U';
  $game->{'C'}{'REQUESTJET'} = 'V';
  $game->{'C'}{'PAYLOAN'} = 'W';
  $game->{'C'}{'ANSWER'} = 'X';
  $game->{'C'}{'DEPOSIT'} = 'Y';
  $game->{'C'}{'PUSH'} = 'Z';
  $game->{'C'}{'QUIT'} = 'a';
  $game->{'C'}{'RENAME'} = 'b';
  $game->{'C'}{'NAME'} = 'c';
  $game->{'C'}{'SACKBITCH'} = 'd';
  $game->{'C'}{'TIPOFF'} = 'e';
  $game->{'C'}{'SPYON'} = 'f';
  $game->{'C'}{'WANTQUIT'} = 'g';
  $game->{'C'}{'CONTACTSPY'} = 'h';
  $game->{'C'}{'KILL'} = 'i';
  $game->{'C'}{'REQUESTSCORE'} = 'j';
  $game->{'C'}{'INIT'} = 'k';
  $game->{'C'}{'DATA'} = 'l';
  $game->{'C'}{'FIGHTPRINT'} = 'm';
  $game->{'C'}{'FIGHTACT'} = 'n';
  $game->{'C'}{'TRADE'} = 'o';
  $game->{'C'}{'CHANGEDISP'} = 'p';
  $game->{'C'}{'NETMESSAGE'} = 'q';
  $game->{'C'}{'NONE'} = 'A';
  $game->{'C'}{'ASKLOAN'} = 'B';
  $game->{'C'}{'COPS'} = 'C';
  $game->{'C'}{'ASKBITCH'} = 'D';
  $game->{'C'}{'ASKGUN'} = 'E';
  $game->{'C'}{'ASKGUNSHOP'} = 'F';
  $game->{'C'}{'ASKPUB'} = 'G';
  $game->{'C'}{'ASKBANK'} = 'H';
  $game->{'C'}{'ASKRUN'} = 'I';
  $game->{'C'}{'ASKRUNFIGHT'} = 'J';
  $game->{'C'}{'ASKSEW'} = 'K';
  $game->{'C'}{'MEETPLAYER'} = 'L';
  $game->{'DT'}{'LOCATION'} = 'A';
  $game->{'DT'}{'DRUG'} = 'B';
  $game->{'DT'}{'GUN'} = 'C';
  $game->{'DT'}{'PRICES'} = 'D';
}

sub read_message_h {
  my ($game) = @_;

  if (open(MESS,$MESSAGE_H)) {
    while (<MESS>) {
      $game->{'C'}{$1} = $2 if (/#define\s+C_(\S+)\s+\'(.)\'/);
      $game->{'DT'}{$1} = $2 if (/#define\s+DT_(\S+)\s+\'(.)\'/);

      # Make the default_message() routine:
      #print "  \$game->{'C'}{'$1'} = '$2';\n" if (/#define\s+C_(\S+)\s+\'(.)\'/);
      #print "  \$game->{'DT'}{'$1'} = '$2';\n" if (/#define\s+DT_(\S+)\s+\'(.)\'/);
    }
    close(MESS);
  } else {
    default_message($game);
  }
}

##################################################
# Main
##################################################
sub main {
  my %game;	# Game data object
  read_message_h(\%game);
  $game{'handle'} = client();
  game_loop(\%game);
  close_client(\%game);
}
main();
