Games-AIBots

 view release on metacpan or  search on metacpan

lib/Games/AIBots.pm  view on Meta::CPAN

     || /^(attempt)[\s\t]+(repair|destruct)$/
     || /^(beam)[\s\t]+(command|fuel|ammo)\s+(.+)$/
     || /^(toggle)[\s\t]+(shield|laymine|cloak)$/
    ) {
        $bot->{'lastcmd'} = join(' ', ucfirst($1), substr($_, $-[2]));
        &{"cmd_$1"}($bot, $2, $3, $4) or @{$bot->{'queue'}} = grep {$_ eq $bot->{'lastcmd'}} @{$bot->{'queue'}};;
        bot_watch($bot) unless $Continue;;
    }
    elsif ($_) {
        warn "Malformed command $_ from ".$bot->{'id'}.", state ".$bot->{'state'};
    }

    $bot->{'dead'} = 1 if $bot->{'life'} <= 0;
    unless ($bot->{'dead'}) {
        tick_cloak($bot);
        obj_move(@{$old}{'x', 'y'}, @{$bot}{'x', 'y'}, bot_char($bot), "_bot$bot->{'id'}", 0, ($bot->{'id'} eq $Watch->{'id'}));
        obj_move(@{$old}{'x', 'y'}, @{$bot}{'x', 'y'}, $bot->{'shield'} ? 'shield' : 'noshield', "_bots$bot->{'id'}", 1);
    }

    $Top->after($Tick_delay / (scalar @Bots), \&Games::AIBots::tick_bot) if $GUI and $Running;
}

sub tick_missile {
    my $missile = shift;
    return if $missile->{'dead'};

    my $bot       = $missile->{'bot'};
    my ($dx, $dy) = delta($missile->{'h'}, 'front');
    my $tag       = "_missile$bot->{'id'}:$missile->{'id'}";

    if (bot_at(@{$missile}{'x', 'y'}) and $missile->{'age'}
        or obj_at($missile->{'x'} += $dx, $missile->{'y'} += $dy) ne '.'
        or ++$missile->{'age'} >= $missile->{'range'})
    {
        detonate($bot, $missile->{'type'}, @{$missile}{'x', 'y'});
        $missile->{'dead'}++;
        $Canvas->delete($tag) if $GUI;
    }
    elsif ($missile->{'age'} > 1) {
        obj_move($missile->{'x'} - $dx, $missile->{'y'} - $dy,
                 @{$missile}{'x', 'y'}, $missile->{'type'}.$missile->{'h'}, $tag, 1);
    }
    else {
        obj_draw(@{$missile}{'x', 'y'}, $missile->{'type'}.$missile->{'h'}, $tag, 1);
    }
}

sub tick_cloak {
    my $bot = shift;
    return unless $bot->{'cloak'};

    if ($bot->{'fuel'} >= $Cloak_fuel and bot_pay($bot, ammo => $Cloak_ammo)) {
        $bot->{'fuel'} -= $Cloak_fuel;
    }
    else {
        $bot->{'cloak'} = 0;
    }
}

sub tick_check {
    my (%alive, $hasfuel, $missiles);
    return if !$Running;

    foreach my $bot (@Bots) {
        $alive{$bot->{'team'} || bot_id($bot)}++ unless $bot->{'dead'};
        $hasfuel++ unless $bot->{'dead'} or $bot->{'fuel'} <= 0;
        foreach my $missile (@{$bot->{'missiles'}}) {
            $missiles++ unless $missile->{'dead'};
        }
    }

    if (!$missiles and (scalar keys(%alive) <= 1) or !$hasfuel) {
        # Game Over
        display('end');

        my %TScore;
        foreach my $bot (@Bots) {
            $bot->{'score'}  += 50 * $bot->{'life'};
            $bot->{'score'}  -= $bot->{'burn'};
            $bot->{'score'}  += 500 / $alive{$bot->{'team'} || bot_id($bot)}
                unless $bot->{'dead'} or (scalar keys(%alive) > 1);
            $TScore{$bot->{'team'} || bot_id($bot)} += $bot->{'score'} || 0;
            $bot->{'lastcmd'} = '**End**';
        }

        my @BScore = sort {$b->{'score'} <=> $a->{'score'}} @Bots;
        my @TScore = sort {$TScore{$b} <=> $TScore{$a}} keys(%TScore);

        if ($GUI) {
            $Btn_stop->configure(-state => 'disabled');
            $Btn_play->configure(-image => 'play');
            $_->configure(-state => 'normal', -background => '#a04444') foreach @Mnu_arg;
            $Top->configure('-title' => "AI Bots v$Games::AIBots::VERSION [Winner:".bot_id($BScore[0])." | Team ".$TScore[0]."] (Tick: $Tick)");
            $Watch->{'id'} = $BScore[0]->{'id'};
            bot_watch($BScore[0]);
        }

        foreach my $bot (@BScore) {
            $Watch->{'id'} = $bot->{'id'};
            bot_watch($bot, 1);
            print "\n" unless $Console and $^O ne 'MSWin32';
        }

        $Running = undef;
        ding('game_over');
        display('winner', bot_id($BScore[0]), $TScore[0]);
    }

    return $Running;
}

# ===========================================================================
# Bot Commands
# ===========================================================================

sub cmd_attempt {
    my ($bot, $action) = @_;

    if ($action eq 'repair') {
        return if $bot->{'shield'} or $bot->{'life'} >= $Max_life;

        if (!int(rand(10))) {
            $bot->{'life'}++;
            obj_flash('repair', @{$bot}{'x', 'y'});
        }
        elsif (!int(rand(20))) {
            $bot->{'burn'}++;
            obj_flash('explode', @{$bot}{'x', 'y'});
        }
    }
    elsif ($action eq 'destruct') {
        my $dmg = $bot->{'life'} * 100 / $Max_life;
        @{$Weapon{'destructh'}}[$DmgS, $DmgN, $BurnS, $BurnN]
            = ($dmg, $dmg, $dmg / 10, $dmg / 10);
        @{$Weapon{'destructs'}}[$DmgS, $DmgN, $BurnS, $BurnN, $ScrS, $ScrN]
            = ($dmg, $dmg, $dmg / 10, $dmg / 10, $dmg * 5, $dmg * 5);
        detonate($bot, 'destruct', @{$bot}{'x', 'y'});
    }

    return 1;
}



( run in 2.771 seconds using v1.01-cache-2.11-cpan-99c4e6809bf )