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 )