Games-FrozenBubble
view release on metacpan or search on metacpan
bin/frozen-bubble view on Meta::CPAN
if ($graphics_level == 3) {
my $player = @PLAYERS == 2 && $::p eq 'rp1' ? 'p2' : $::p;
$fun->($pinguin{$player}{$pdata{$::p}{ping_right}{state}}[$pdata{$::p}{ping_right}{img}],
$POS{$player}{left_limit}+$POS{$player}{pinguin}{x}, $POS{$player}{pinguin}{'y'});
}
}
handle_progress($::p);
#- chat message in mp
if (is_mp_game() && $pdata{$::p}{chat_msg_delay}) {
$pdata{$::p}{chat_msg_delay}--;
if (!$pdata{$::p}{chat_msg_delay}) {
my $img = @PLAYERS == 2 ? $imgbin{void_chat_small_p2} : member($::p, qw(rp1 rp3)) ? $imgbin{void_chat_small_rp1_rp3} : $imgbin{void_chat_small_rp2_rp4};
remove_image_from_background($img, $POS{$::p}{chatting}{x}, $POS{$::p}{chatting}{'y'});
$pdata{current_chat_messages}{$::p} = undef;
print_next_bubble($next_bubble{$::p}{img}, $::p);
if (member($::p, 'rp3', 'rp4')) {
print_scores($background);
print_scores($app);
}
}
}
#- moving bubbles --> I want them on top of the rest
foreach (@{$malus_bubble{$::p}}, @{$falling_bubble{$::p}}, @{$exploding_bubble{$::p}}) {
$fun->($_->{img}, $_->{'x'}, $_->{'y'});
}
};
if ($levels{current} eq 'mp_train' && $pdata{state} eq 'game') {
if ($fun ne \&erase_image) {
my $drect = SDL::Rect->new($mp_train_xpos, $mp_train_ypos, $imgbin{void_mp_training}->w, 30);
SDL::Video::blit_surface($background_orig, $drect, $background, $drect);
mp_train_print_time();
SDL::Video::blit_surface($background, $drect, $app, $drect);
push @update_rects, $drect;
my $seconds = mp_train_time_left();
if ($seconds == 0) {
put_image($imgbin{void_panel}, $MENUPOS{xpos_panel}, $MENUPOS{ypos_panel});
my $y = $MENUPOS{ypos_panel} + 30;
my @messages = ('', '', '', '', loc("Your score after two minutes:"), '', $pdata{p1}{score}, '', loc("Press any key."));
foreach (@messages) {
print_('menu', $app, $MENUPOS{xpos_panel}, $y, $_, $imgbin{void_panel}->w, 'center');
$y += $smg_lineheight;
}
SDL::Video::update_rect($app, 0, 0, 0, 0);
play_sound('cancel');
Games::FrozenBubble::CStuff::fbdelay(1000);
SDL::Events::pump_events() while SDL::Events::poll_event($event) != 0;
grab_key() eq SDLK_ESCAPE() and die 'quit';
handle_new_hiscores();
die 'new_game';
}
}
}
}
#- extract it from "handle_graphics" to optimize a bit animations
sub update_malus($$) {
my ($fun, $p) = @_;
my $malus_nb = @{$pdata{$p}{malus}};
my $y_shift = 0;
while ($malus_nb > 0) {
my $print = sub($) {
my ($type) = @_;
my $type_real = translate_mini_image($type);
$fun->($type, $POS{$p}{malus}{x} - $type_real->w/2, $POS{$p}{malus}{'y'} - $y_shift - $type_real->h);
$y_shift += $type_real->h - 1;
};
if ($malus_nb >= 7) {
$print->($malus_gfx{tomate});
$malus_nb -= 7;
} else {
$print->($malus_gfx{banane});
$malus_nb--;
}
}
}
sub malus_change($$) {
my ($numb, $player) = @_;
return if $numb == 0 || is_1p_game() && $levels{current} ne 'mp_train';
if ($levels{current} eq 'mp_train' && $numb > 0) {
$pdata{p1}{score} += $numb;
print_scores($app);
print_scores($background);
return;
}
if ($numb > 0) {
#- malus are adding up
if (!is_mp_game()) {
iter_players_ {
if ($::p_ ne $player) {
update_malus(\&remove_image_from_background, $::p_);
push @{$pdata{$::p_}{malus}}, ($frame) x $numb;
update_malus(\&put_image_to_background, $::p_);
}
};
} else {
if (is_local_player($player)) { #- remote players handled when receiving the 'g' message
if (!$pdata{sendmalustoone}) {
my @living = living_players();
if (@living > 1) {
$numb = int($numb/(@living-1) + 0.99);
iter_players_ {
if ($::p_ ne $player && member($::p_, @living)) {
is_mp_game() and Games::FrozenBubble::Net::gsend("g$pdata{$::p_}{nick}:$numb");
update_malus(\&remove_image_from_background, $::p_);
push @{$pdata{$::p_}{malus}}, ($frame) x $numb;
update_malus(\&put_image_to_background, $::p_);
}
};
}
} else {
my $p = $pdata{sendmalustoone};
is_mp_game() and Games::FrozenBubble::Net::gsend("g$pdata{$p}{nick}:$numb");
iter_players_ { #- get mini graphics
if ($::p_ eq $p) {
bin/frozen-bubble view on Meta::CPAN
}
sub print_ {
my ($kind, $surface, $x, $y, $text, $size, $alignment, $callback) = @_;
printf("print_: " . join(' ', (caller(1))) . " $text\n") if $ENV{FB_DEBUG};
exists $pangocontext{$kind} or die "$kind is no kind\n";
if ($size) {
#- instead of segfaulting
my $minsize = width($kind, $text);
if ($minsize > $size) {
$size = $minsize;
}
}
my $surf = Games::FrozenBubble::CStuff::sdlpango_draw_givenalignment($pangocontext{$kind}{context_bg}, $text, $size || -1, $alignment || 'left');
if ($callback) {
if (!$callback->('about-to-draw', $surf)) {
#- callback said do not draw
return;
}
}
SDL::Video::blit_surface($surf, SDL::Rect->new(0, 0, $surf->w, $surf->h), $surface, SDL::Rect->new($x + 1, $y + 1, $surf->w, $surf->h));
$surf = Games::FrozenBubble::CStuff::sdlpango_draw_givenalignment($pangocontext{$kind}{context_fg}, $text, $size || -1, $alignment || 'left');
#printf("sdlpango_draw_givenalignment: %s, %s, %s, %s\n", $kind, $text, $size || -1, $alignment || 'left');
#printf("SDL::Rect->new($x, $y, " . $surf->w . ", " . $surf->h . ")\n");
SDL::Video::blit_surface($surf, SDL::Rect->new(0, 0, $surf->w, $surf->h), $surface, SDL::Rect->new($x, $y, $surf->w, $surf->h));
}
sub width {
my ($kind, $text) = @_;
exists $pangocontext{$kind} or die "$kind is no kind\n";
my $size = Games::FrozenBubble::CStuff::sdlpango_getsize($pangocontext{$kind}{context_fg}, $text, -1);
return $size->[0];
}
sub mp_disconnect_with_reason {
my (@messages) = @_;
put_image($imgbin{void_panel}, $MENUPOS{xpos_panel}, $MENUPOS{ypos_panel});
my $y = $MENUPOS{ypos_panel} + 30;
foreach (@messages) {
print_('menu', $app, $MENUPOS{xpos_panel} + 10, $y, $_, $imgbin{void_panel}->w - 20, 'center');
$y += $smg_lineheight;
}
SDL::Video::update_rect($app, 0, 0, 0, 0);
play_sound('cancel');
Games::FrozenBubble::CStuff::fbdelay(2000);
SDL::Events::pump_events() while SDL::Events::poll_event($event) != 0;
grab_key();
die 'quit';
}
sub check_mp_connection {
if (!Games::FrozenBubble::Net::isconnected()) {
if ($pdata{gametype} eq 'lan') {
mp_disconnect_with_reason('', '', '', '', loc("Lost connection to server!"), '', loc("Hoster aborted the game."));
} else {
mp_disconnect_with_reason('', '', '', '', loc("Lost connection to server!"), '', loc("Your lag is probably too high."));
}
}
}
sub update_say_mp {
put_image($imgbin{void_chat}, $POS{p1}{chatting}{x}, $POS{p1}{chatting}{'y'});
callback_entry('print', { xpos => $POS{p1}{chatting}{x} + 15, ypos => $POS{p1}{chatting}{'y'} + 5, font => 'ingame_chat', maxlen => $imgbin{void_chat}->w - 30 });
push @update_rects, $apprects{main};
}
sub cleanup_chatting {
$pdata{p1}{chatting} = 0;
SDL::Events::enable_key_repeat(0, 0);
remove_image_from_background($imgbin{void_chat}, $POS{p1}{chatting}{x}, $POS{p1}{chatting}{'y'});
print_next_bubble($next_bubble{p1}{img}, 'p1');
redraw_attackingme();
}
sub set_sendmalustoone {
my ($whoto) = @_;
$pdata{sendmalustoone} = undef;
iter_distant_players_ {
remove_image_from_background($imgbin{attack}{$::p_}, $POS{$::p_}{attack}{x}, $POS{$::p_}{attack}{'y'});
};
if (member($whoto, living_players()) && $pdata{p1}{state} ne 'lost') {
$pdata{sendmalustoone} = $whoto;
put_image_to_background($imgbin{attack}{$pdata{sendmalustoone}}, $POS{$pdata{sendmalustoone}}{attack}{x}, $POS{$pdata{sendmalustoone}}{attack}{'y'});
}
if ($pdata{protocollevel} >= 1) {
Games::FrozenBubble::Net::gsend("A$pdata{$pdata{sendmalustoone}}{nick}");
}
}
sub redraw_attackingme {
$pdata{p1}{chatting} and return;
my $xpos = $POS{p1}{attackme}{x};
my $drect = SDL::Rect->new($xpos, $POS{p1}{attackme}{'y'}, 3*24 + $imgbin{attackme}{rp1}->w, $imgbin{attackme}{rp1}->h);
SDL::Video::blit_surface($background_orig, $drect, $background, $drect);
SDL::Video::blit_surface($background_orig, $drect, $app, $drect);
push @update_rects, $drect;
foreach my $attackingme (@{$pdata{attackingme}}) {
put_image_to_background($imgbin{attackme}{$attackingme}, $xpos, $POS{p1}{attackme}{'y'});
$xpos += 24;
}
}
sub handle_mp_messages {
my ($msg) = @_;
#- in order to keep ordering of actions executed in update_game, we must tolerate only one action at a time
my $check_action_possible = sub {
my ($m, $player) = @_;
#- we check also the presence of malus bubbles, because if the malus order has lagged much
#- we might receive a fire or even a stick command before the malus bubbles are sticked,
#- this would provoke a local inconsistency; same for chain reacted bubbles not finished yet
if ($actions{$player}{mp_fire}
|| $actions{$player}{mp_stick}
|| @{$malus_bubble{$player}}
|| $chainreaction && any { exists $_->{chaindestx} } @{$falling_bubble{$player}}) {
unshift @$msg, $m;
return 0;
} else {
return 1;
}
};
bin/frozen-bubble view on Meta::CPAN
if ($pdata{sendmalustoone} eq $player || $player eq 'p1') {
set_sendmalustoone(undef);
}
}
if ($pdata{$player}{left}) {
if (is_distant_player($player)) {
put_image_to_background(mini_graphics($player) ? $imgbin{"left_${player}_mini"} : $imgbin{left_rp1},
$POS{$player}{left}{x}, $POS{$player}{left}{y}); #}}
}
@{$sticked_bubbles{$player}} = ();
play_sound('cancel');
} else {
play_sound('lose');
}
} else {
play_sound('lose');
$pdata{state} = "lost $player";
is_2p_game() and win($player eq 'p1' ? 'p2' : 'p1');
}
ret:
}
sub verify_if_end {
iter_players {
if ($pdata{state} eq 'game' && any { $_->{cy} > 11 } @{$sticked_bubbles{$::p}}) {
lose($::p);
}
};
if (is_1p_game() && $levels{current} ne 'mp_train' && @{$sticked_bubbles{$PLAYERS[0]}} == 0) {
put_image_to_background($imgbin{win_panel_1player}, $POS{centerpanel}{x}, $POS{centerpanel}{'y'});
$pdata{state} = "won $PLAYERS[0]";
$pdata{$PLAYERS[0]}{ping_right}{state} = 'win';
$pdata{$PLAYERS[0]}{ping_right}{img} = 0;
if ($levels{current} ne 'random') {
$levels{current} and $levels{current}++;
if ($levels{current} && !$levels{$levels{current}}) {
$levels{current} = 'WON';
@{$falling_bubble{$PLAYERS[0]}} = @{$exploding_bubble{$PLAYERS[0]}} = ();
die 'quit';
}
}
}
}
sub print_hurry($;$) {
my ($player, $dont_save_background) = @_;
$player = @PLAYERS == 2 && $player eq 'rp1' ? 'p2' : $player;
my $t = switch_image_on_background($imgbin{hurry}{$player}, $POS{$player}{left_limit} + $POS{$player}{hurry}{x}, $POS{$player}{hurry}{'y'}, 1);
$dont_save_background or $pdata{$player}{hurry_save_img} = $t;
}
sub remove_hurry($) {
my ($player) = @_;
$player = @PLAYERS == 2 && $player eq 'rp1' ? 'p2' : $player;
$pdata{$player}{hurry_save_img} and
switch_image_on_background($pdata{$player}{hurry_save_img}, $POS{$player}{left_limit} + $POS{$player}{hurry}{x}, $POS{$player}{hurry}{'y'});
$pdata{$player}{hurry_save_img} = undef;
}
sub update_lost {
my ($player) = @_;
return if odd($frame);
if (@{$sticked_bubbles{$player}}) {
my $b = shift @{$sticked_bubbles{$player}};
put_image_to_background($bubbles_anim{lose}, --$b->{'x'}, --$b->{'y'});
if (@{$sticked_bubbles{$player}} == 0) {
if ($graphics_level == 1 && $pdata{state} =~ /^lost (.*)/ && !is_1p_game()) {
put_image_to_background($imgbin{win}{$player eq 'p1' ? 'p2' : 'p1'}, $POS{centerpanel}{x}, $POS{centerpanel}{'y'});
}
if (is_1p_game()) {
put_image_to_background($imgbin{lose}, $POS{centerpanel}{'x'}, $POS{centerpanel}{'y'});
play_sound('noh');
}
}
}
if (!is_mp_game()) {
SDL::Events::pump_events();
while (SDL::Events::poll_event($event) != 0) {
if ($event->type == SDL_QUIT) {
cleanup_and_exit();
}
if ($event->type == SDL_KEYDOWN && $event->key_sym == SDLK_ESCAPE) {
die 'new_game';
}
if (!@{$sticked_bubbles{$player}}) {
if ($event->type == SDL_KEYDOWN || $event->type == SDL_JOYBUTTONUP) {
die 'new_game';
}
}
}
}
my $still_sticked = sum(map { @{$sticked_bubbles{$_}} } @PLAYERS);
if ($pdata{state} eq 'won ' && $still_sticked == 1) {
put_image($imgbin{void_panel}, $MENUPOS{xpos_panel}, $MENUPOS{ypos_panel});
print_('menu', $app, $MENUPOS{xpos_panel}, $MENUPOS{ypos_panel} + 30, loc("Draw game!"), $imgbin{void_panel}->w - 20, 'center');
SDL::Video::update_rect($app, 0, 0, 0, 0);
}
}
sub update_won {
my ($player) = @_;
return if odd($frame);
iter_players { #- need iter_players to get the small graphics change for free if we're in multiplayer
if ($::p eq $player) {
if (@{$sticked_bubbles{$::p}} && $graphics_level > 1) {
my $b = shift @{$sticked_bubbles{$::p}};
destroy_bubbles($::p, $b);
remove_image_from_background($b->{img}, $b->{'x'}, $b->{'y'});
#- be sure to redraw at least upper line
foreach (@{$b->{neighbours}}) {
next if !member($_, @{$sticked_bubbles{$::p}});
put_image_to_background($_->{img}, $_->{'x'}, $_->{'y'});
}
} else {
@{$sticked_bubbles{$::p}} = ();
}
}
};
}
sub decode_postgame_message($) {
my ($msg) = @_;
my $player = $pdata{id2p}{$msg->{id}};
$player ||= 'UNKNOWN';
if ($msg->{msg} =~ /^F(.*)/) {
$pdata{$player}{still_game_messages} = 0;
dbgnet("decoded postgame message: from=$player msg=finished $1");
return "$player finished $1";
} elsif ($pdata{$player}{still_game_messages}) {
dbgnet("decoded postgame message: from=$player msg=gamemsg");
return "$player gamemsg";
} elsif ($msg->{msg} eq 'n') {
$pdata{$player}{ready4newgame} = 1;
dbgnet("decoded postgame message: from=$player msg=newgame");
return "$player newgame";
} else {
if ($msg->{msg} ne 'l') {
print "Postgame 'other' message from $player not a leave - $msg->{msg} - should not!\n";
}
dbgnet("decoded postgame message: from=$player msg=other");
return "$player other";
}
}
#- ----------- mainloop helper --------------------------------------------
sub update_game() {
if ($pdata{state} eq 'game') {
handle_game_events();
iter_players {
if ($pdata{$::p}{state} eq 'lost') {
update_lost($::p);
} elsif ($pdata{$::p}{state} eq 'ingame') {
$actions{$::p}{left} and $angle{$::p} += $LAUNCHER_SPEED;
$actions{$::p}{right} and $angle{$::p} -= $LAUNCHER_SPEED;
if ($actions{$::p}{center}) {
if ($angle{$::p} >= $PI/2 - $LAUNCHER_SPEED
&& $angle{$::p} <= $PI/2 + $LAUNCHER_SPEED) {
$angle{$::p} = $PI/2;
} else {
$angle{$::p} += ($angle{$::p} < $PI/2) ? $LAUNCHER_SPEED : -$LAUNCHER_SPEED;
}
}
($angle{$::p} < 0.1) and $angle{$::p} = 0.1;
($angle{$::p} > $PI-0.1) and $angle{$::p} = $PI-0.1;
if (is_mp_game() && is_local_player($::p) && ($actions{$::p}{left} || $actions{$::p}{right} || $actions{$::p}{center})) {
Games::FrozenBubble::Net::gsend(sprintf("a%.2f", $angle{$::p}));
}
if (every { ! exists $_->{chaindestx} } @{$falling_bubble{$::p}}) {
$pdata{$::p}{hurry}++;
}
if ((!$no_time_limit || is_mp_game()) && $pdata{$::p}{hurry} > $TIME_HURRY_WARN) {
my $oddness = odd(int(($pdata{$::p}{hurry}-$TIME_HURRY_WARN)/(500/$TARGET_ANIM_SPEED))+1);
if ($pdata{$::p}{hurry_oddness} xor $oddness) {
if ($oddness) {
play_sound('hurry');
print_hurry($::p);
} else {
remove_hurry($::p)
}
}
$pdata{$::p}{hurry_oddness} = $oddness;
}
if ($actions{$::p}{mp_fire}
|| (is_local_player($::p)
&& ($actions{$::p}{fire} || ((!$no_time_limit || is_mp_game()) && $pdata{$::p}{hurry} == $TIME_HURRY_MAX))
&& !$launched_bubble{$::p}
&& !(any { exists $_->{chaindestx} } @{$falling_bubble{$::p}})
&& !@{$malus_bubble{$::p}})) {
play_sound('launch');
$launched_bubble{$::p} = $tobe_launched{$::p};
$launched_bubble{$::p}->{direction} = $angle{$::p};
$tobe_launched{$::p} = undef;
$actions{$::p}{fire} = 0;
$actions{$::p}{hadfire} = 1;
$pdata{$::p}{hurry} = 0;
remove_hurry($::p);
if (is_local_player($::p)) {
do {
$pdata{$::p}{nextcolor} = int(rand(@bubbles_images));
} while (!validate_nextcolor($pdata{$::p}{nextcolor}, $::p) && @{$sticked_bubbles{$::p}});
}
if (is_mp_game()) {
if (is_local_player($::p)) {
( run in 3.597 seconds using v1.01-cache-2.11-cpan-75ffa21a3d4 )