#! perl use Scalar::Util; # minesweeper extension. dumb. sub result { my ($ob, $status) = @_; if (my $teleport = $ob->{options}{"teleport_$status"}) { my ($x, $y, $damned) = split /,/, $teleport; my $pl = cf::player::find $ob->{player}; $pl->ob->transfer ($x, $y); $pl->savebed ($pl->ob->map->path, $x, $y) if $ob->{options}{"set_savebed_$status"}; } } sub apply { my ($who) = @_; my $meta = $who->{meta} or return; my $map = $meta->{map}; my ($x, $y) = ($who->x - $meta->x, $who->y - $meta->y); $who->{visible} = 1; if ($who->{bomb}) { result $meta, "failure" if $meta->{todo}; } else { $meta->{todo}--; # if <= 0, finished my @neigh; for my $y ($y - 1 .. $y + 1) { next if $y < 0 || $y > $#{$map->[0]}; for my $x ($x - 1 .. $x + 1) { next if $x < 0 || $x > $#$map; push @neigh, $map->[$x][$y]; } } my $bombs = grep $_->{bomb}, @neigh; my $ob = $map->[$x][$y] = cf::object::new "minesweeper-$bombs"; $ob->insert_ob_in_map_at ($who->map, undef, cf::INS_ABOVE_FLOOR_ONLY, $who->x, $who->y); push @{ $meta->{queue} }, grep !$_->{visible}, @neigh unless $bombs; $who->destroy; } 1 } cf::register_attachment minesweeper => on_tick => sub { my ($self) = @_; if (my $queue = $self->{queue}) { my $count = 4; while (@$queue) { my $i = int rand @$queue; my $ob = splice @$queue, $i, 1, (); next if $ob->{visible}; apply $ob or next; result $self, "success" unless $self->{todo}; $count-- or last; } } else { my %arg = %{ $self->{options} = delete $self->{minesweeper} }; $self->{queue} = []; my $map = $self->{map} = []; for my $x (0 .. $arg{width} - 1) { for my $y (0 .. $arg{height} - 1) { my $ob = $map->[$x][$y] = cf::object::new "minesweeper-unknown"; $ob->name ("apply to try your luck or intelligence"); Scalar::Util::weaken ($ob->{meta} = $self); $ob->attach ("minesweeper_field"); $ob->insert_ob_in_map_at ($self->map, undef, cf::INS_ABOVE_FLOOR_ONLY, $self->x + $x, $self->y + $y); } } # #tiles that need to be uncovered $self->{todo} = $arg{width} * $arg{height} - $arg{bombs}; for (1 .. $arg{bombs}) { my $x = int rand $arg{width}; my $y = int rand $arg{height}; redo if $map->[$x][$y]{bomb}; $map->[$x][$y]{bomb} = 1; } } cf::override; }, ; cf::register_attachment minesweeper_field => on_apply => sub { my ($ob, $who) = @_; $ob->{meta}{player} = $who->name; push @{$ob->{meta}{queue}}, $ob; cf::override 1; }, ;