Games-Risk

 view release on metacpan or  search on metacpan

lib/Games/Risk/Controller.pm  view on Meta::CPAN

    # don't have at least 50% luck to win with it. FIXME: customizable?
    my $nbdice_dst = $nbdice_src > 1
        ? $attack[1] > 4 ? 1 : 2
        : 2; # defend with 2 dices if attacker has only one
    $nbdice_dst = min $armies_dst, $nbdice_dst;
    my @defence;
    push( @defence, int(rand(6)+1) ) for 1 .. $nbdice_dst;
    @defence = reverse sort @defence;

    # compute losses
    my @losses  = (0, 0);
    $losses[ $attack[0] <= $defence[0] ? 0 : 1 ]++;
    $losses[ $attack[1] <= $defence[1] ? 0 : 1 ]++
        if $nbdice_src >= 2 && $nbdice_dst == 2;

    # update countries
    $src->set_armies( $src->armies - $losses[0] );
    $dst->set_armies( $dst->armies - $losses[1] );

    # post damages
    # FIXME: only for human player?
    $h->send_to_all('attack_info', $src, $dst, \@attack, \@defence);

    my $wait = $player->type eq 'ai' ? $ATTACK_WAIT_AI : $ATTACK_WAIT_HUMAN;
    K->delay_set( '_attack_done' => $wait, $src, $dst );
}


#
# event: attack_end();
#
# fired when a player does not want to attack anymore during her turn.
#
sub _onpub_attack_end {
    K->delay_set( '_attack_end' => $WAIT );
}


#
# event: attack_move($src, $dst, $nb)
#
# request to invade $dst from $src with $nb armies.
#
sub _onpub_attack_move {
    my ($h, $src, $dst, $nb) = @_[HEAP, ARG0..$#_];

    # FIXME: check player is curplayer
    # FIXME: check $src & $dst
    # FIXME: check $nb is more than min
    # FIXME: check $nb is less than max - 1

    my $looser = $dst->owner;

    # update the countries
    $src->set_armies( $src->armies - $nb );
    $dst->set_armies( $nb );
    $dst->set_owner( $src->owner );

    # update the gui
    $h->send_to_all('chnum', $src);
    $h->send_to_all('chown', $dst, $looser);

    # check if previous $dst owner has lost.
    if ( scalar($looser->countries) == 0 ) {
        # omg! one player left
        $h->player_lost($looser);
        $h->send_to_all('player_lost', $looser);

        # distribute cards from lost player to the one who crushed her
        my @cards = $looser->cards->all;
        my $player = $h->curplayer;
        foreach my $card ( @cards ) {
            $looser->cards->del($card);
            $player->cards->add($card);
            $h->send_to_one($player, 'card_add', $card);
            $h->send_to_one($looser, 'card_del', $card);
        }

        # check if game is over
        my @active = $h->players_active;
        if ( scalar @active == 1 ) {
            $h->send_to_all('game_over', $player);
            return;
        }
    }

    # continue attack
    $h->send_to_one($h->curplayer, 'attack');
}


#
# event: cards_exchange($card, $card, $card)
#
# exchange the cards against some armies.
#
sub _onpub_cards_exchange {
    my ($h, @cards) = @_[HEAP, ARG0..$#_];
    my $player = $h->curplayer;

    # FIXME: check player is curplayer
    # FIXME: check cards belong to player
    # FIXME: check we're in place_armies phase

    # compute player's bonus
    my $combo = join '', sort map { substr $_->type, 0, 1 } @cards;
    my %bonus;
    $bonus{$_} = 10 for qw{ aci acj aij cij ajj cjj ijj Jérôme Quelin };
    $bonus{$_} = 8  for qw{ aaa aaj };
    $bonus{$_} = 6  for qw{ ccc ccj };
    $bonus{$_} = 4  for qw{ iii iij };
    my $bonus = $bonus{ $combo } // 0;

    # wrong combo
    return if $bonus == 0;

    # trade the armies
    my $armies = $h->armies + $bonus;
    $h->armies($armies);

    # signal that player has some more armies...

lib/Games/Risk/Controller.pm  view on Meta::CPAN

# is ready before moving on to next phase (assign countries).
#
sub _onpub_player_created {
    my ($h, $player) = @_[HEAP, ARG0];
    delete $h->wait_for->{ $player->name };

    # go on to the next phase
    K->yield( '_players_created' ) if scalar keys %{ $h->wait_for } == 0;
}


#
# event: quit()
#
# fired by startup window to quit the game.
#
sub _onpub_quit {
    K->alias_remove('risk');
}

#
# event: shutdown()
#
# fired when board window has been closed, requesting all ais and
# remaining windows to shutdown too.
#
sub _onpub_shutdown {
    my $h = $_[HEAP];

    # remove all possible pending events.
    K->alarm_remove_all;

    # close all ais & windows
    $h->send_to_all('shutdown');
    $h->destroy;
}


# -- private events - game states

#
# distribute randomly countries to players.
# FIXME: what in the case of a loaded game?
# FIXME: this can be configured so that players pick the countries
# of their choice, turn by turn
#
sub _onpriv_assign_countries {
    my $h = $_[HEAP];

    # initial random assignment of countries
    my @players   = $h->players;
    my @countries = shuffle $h->map->countries;
    while ( my $country = shift @countries ) {
        # rotate players
        my $player = shift @players;
        push @players, $player;

        # store new owner & place one army to start with
        $country->set_owner($player);
        $country->set_armies(1);
        $h->send_to_all('chown', $country);
    }

    # go on to the next phase
    K->yield( '_countries_assigned' );
}


#
# start the attack phase for curplayer
#
sub _onpriv_attack {
    my $h = $_[HEAP];
    $h->send_to_one($h->curplayer, 'attack');
}


#
# event: _attack_done($src, $dst)
#
# check the outcome of attack of $dst from $src. only used as a
# temporization, so this handler will always serve the same event.
#
sub _onpriv_attack_done {
    my ($h, $src, $dst) = @_[HEAP, ARG0..$#_];

    my $player = $h->curplayer;

    # update gui
    $h->send_to_all('chnum', $src);
    $h->send_to_all('chnum', $dst);

    # check outcome
    if ( $dst->armies <= 0 ) {
        # all your base are belong to us! :-)

        # distribute a card if that's the first successful attack in the
        # player's turn.
        if ( not $h->got_card ) {
            $h->got_card(1);
            my $card = $h->map->cards->get;
            $player->cards->add($card);
            $h->send_to_one($player, 'card_add', $card);
        }

        # move armies to invade country
        if ( $src->armies - 1 == $h->nbdice ) {
            # erm, no choice but move all remaining armies
            K->yield( 'attack_move', $src, $dst, $h->nbdice );

        } else {
            # ask how many armies to move
            $h->send_to_one($player, 'attack_move', $src, $dst, $h->nbdice);
        }

    } else {
        $h->send_to_one($player, 'attack');
    }
}




( run in 1.472 second using v1.01-cache-2.11-cpan-71847e10f99 )