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 )