diff --git a/lib/NetHack/Item.pm b/lib/NetHack/Item.pm index 42e0d98..188e086 100644 --- a/lib/NetHack/Item.pm +++ b/lib/NetHack/Item.pm @@ -293,6 +293,9 @@ sub extract_stats { $ # anchor }x; + confess "Couldn't parse $raw" + unless defined($stats{item}) && length($stats{item}); + # this canonicalization must come early if ($stats{item} =~ /^potions? of ((?:un)?holy) water$/) { $stats{item} = 'potion of water'; @@ -313,11 +316,10 @@ sub extract_stats { if ($self->has_pool && ($stats{item} eq $self->pool->fruit_name || $stats{item} eq $self->pool->fruit_plural)) { $stats{item} = $self->pool->fruit_name; # singularize - $stats{is_custom_fruit} = 1; $stats{type} = 'food'; } - else { - $stats{is_custom_fruit} = 0; + elsif ($self->has_pool && $self->pool->allow_other_fruit_names) { + $stats{type} = 'food'; } confess "Unknown item type for '$stats{item}' from $raw" @@ -375,6 +377,8 @@ sub extract_stats { $stats{$_} = '' if !defined($stats{$_}); } + $stats{is_custom_fruit} = 0; + return \%stats; } @@ -386,7 +390,7 @@ sub parse_raw { # exploit the fact that appearances don't show up in the spoiler table as # keys - $self->_set_appearance_and_identity($stats->{item}); + $self->_set_appearance_and_identity($stats); $self->_rebless_into($stats->{type}, $self->subtype); @@ -468,12 +472,15 @@ sub is_artifact { } sub _set_appearance_and_identity { - my $self = shift; - my $best_match = shift; + my $self = shift; + my $stats = shift; + + my $best_match = $stats->{item}; if ($self->has_pool && $best_match eq $self->pool->fruit_name) { $self->identity("slime mold"); $self->appearance($best_match); + $stats->{is_custom_fruit} = 1; } elsif (my $spoiler = $self->spoiler_class->spoiler_for($best_match)) { if ($spoiler->{artifact}) { @@ -491,7 +498,11 @@ sub _set_appearance_and_identity { $self->appearance($best_match); my @possibilities = $self->possibilities; if (@possibilities == 1 && $best_match ne $possibilities[0]) { - $self->_set_appearance_and_identity($possibilities[0]); + $stats->{item} = $possibilities[0]; + $self->_set_appearance_and_identity($stats); + } + if ($self->identity && $self->identity eq 'slime mold') { + $stats->{is_custom_fruit} = 1; } } } @@ -506,7 +517,12 @@ sub possibilities { return $self->tracker->possibilities if $self->has_tracker; - return sort @{ $self->spoiler_class->possibilities_for_appearance($self->appearance) }; + my @possibilities = @{ $self->spoiler_class->possibilities_for_appearance($self->appearance) || [] }; + if (@possibilities == 0 && $self->has_pool && $self->pool->allow_other_fruit_names) { + $self->identity('slime mold'); + @possibilities = ($self->appearance); + } + return sort @possibilities; } sub spoiler { diff --git a/lib/NetHack/ItemPool.pm b/lib/NetHack/ItemPool.pm index 952bb2d..72a4702 100644 --- a/lib/NetHack/ItemPool.pm +++ b/lib/NetHack/ItemPool.pm @@ -21,6 +21,11 @@ has fruit_plural => ( default => 'slime molds', ); +has allow_other_fruit_names => ( + is => 'ro', + isa => 'Bool', +); + has artifacts => ( is => 'ro', isa => 'HashRef', diff --git a/t/606-fruit.t b/t/606-fruit.t index 538e3ee..0337359 100644 --- a/t/606-fruit.t +++ b/t/606-fruit.t @@ -1,6 +1,7 @@ #!/usr/bin/env perl use lib 't/lib'; use Test::NetHack::Item; +use Test::Fatal; my $slime_pool = NetHack::ItemPool->new; my $slime_mold = $slime_pool->new_item("a slime mold"); @@ -15,6 +16,12 @@ ok($molds->is_custom_fruit, "slime molds is custom fruit"); is($molds->appearance, 'slime mold'); is($molds->identity, 'slime mold'); +like( + exception { $slime_pool->new_item("a server") }, + qr/^Unknown item type for 'server' from a server/, + "we don't accept any random fruit type" +); + my $brain_pool = NetHack::ItemPool->new( fruit_name => "brain", @@ -32,6 +39,7 @@ ok($brains->is_custom_fruit, "brains is custom fruit"); is($brains->appearance, 'brain'); is($brains->identity, 'slime mold'); + my $child_pool = NetHack::ItemPool->new( fruit_name => "child", fruit_plural => "children", @@ -48,4 +56,35 @@ ok($children->is_custom_fruit, "children is custom fruit"); is($children->appearance, 'child'); is($children->identity, 'slime mold'); + +my $any_pool = NetHack::ItemPool->new( + allow_other_fruit_names => 1, +); + +my $server = $any_pool->new_item("a server"); +is($server->nutrition, 250); +ok($server->is_custom_fruit, "server is custom fruit"); +is($server->appearance, 'server'); +is($server->identity, 'slime mold'); + +my $servers = $any_pool->new_item("3 servers"); +is($servers->nutrition, 250); +ok($servers->is_custom_fruit, "servers is custom fruit"); +{ local $TODO = "we don't singularize properly yet"; +is($servers->appearance, 'server'); +} +is($servers->identity, 'slime mold'); + +my $any_slime_mold = $any_pool->new_item("a slime mold"); +is($any_slime_mold->nutrition, 250); +ok($any_slime_mold->is_custom_fruit, "slime mold is custom fruit"); +is($any_slime_mold->appearance, 'slime mold'); +is($any_slime_mold->identity, 'slime mold'); + +my $any_molds = $any_pool->new_item("3 slime molds"); +is($any_molds->nutrition, 250); +ok($any_molds->is_custom_fruit, "slime molds is custom fruit"); +is($any_molds->appearance, 'slime mold'); +is($any_molds->identity, 'slime mold'); + done_testing;