The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

NetHack::PriceID - identify NetHack items using shopkeepers

VERSION

version 0.05

SYNOPSIS

    use NetHack::PriceID 'priceid';
    print join ', ', priceid(
        type   => '?',
        amount => 100,
        in     => 'sell',
    );
    # amnesia, create monster, earth, taming

DESCRIPTION

NetHack, the game of princes, has a large item-identification subgame. The quickest way to gauge how useful an item is is to "price identify" it. This involves trying to buy or sell the item in a store, which tells you its price. Item types (scrolls, potions, wands, etc) are each divided into about five price groups -- price IDing cuts down a large number of possible identities of an item.

The calculations for price IDing aren't that difficult, but making sure to get all the edge cases (such as trying to identify items while the shopkeeper is attacking you -- and charging you more money) can be twiddly.

This module also comes with a priceid script.

FUNCTIONS

No functions are exported by default. Any of the following functions may be exported in the usual manner.

priceid PARAMHASH

This is the method most people will be using. It will transform an amount and other information into possible identities. Its arguments are passed as a hash:

type => scroll|ring|wand|...|?|=|/|... (required)

The item type. Valid values are the type name or its glyph: scroll (?), ring (=), wand (/), amulet ("), spellbook (+), potion (!), tool ((), or armor ([). Tools are broken down further into bag, lamp, flute, and horn. Armor is broken down further into cloak, helmet, gloves, boots. Not specifying a type, or specifying an invalid type, will cause an error to be thrown.

amount => INT (required)

The amount ("cost") of the item. How the priceid function interprets this amount is dependent on the in parameter. Not specifying an amount will cause an error to be thrown.

in => buy|sell|base (default: base)

The type of operation. base assumes the amount is the base price. buy assumes the amount is the amount of money the shopkeeper is charging you for the item. sell assumes the amount is the number of Zorkmids the shopkeeper is willing to give you in exchange for the item.

charisma => 3..25 (required for 'buy')

The charisma of the character. Base and sell prices are independent of charisma, so it's required only for buying. This will croak if you try to buy price-ID without setting the charisma.

out => base|names|both (default: names)

The output format. base will return 0, 1, or 2 possible base prices that the input can possibly be. Buying and selling always map to two prices, but usually one of those prices has no items, so it is not given. names will return the actual names of the possible items. both will return a list of array references with the first element of each being the base price, and following elements being the item names.

tourist => BOOL (default: false)

Determines whether the character suffers from the "tourist" surcharge. Shopkeepers (as they presumably do in real life) will charge extra if they think you're a tourist. Characters that are in the tourist class and less than experience level 15 suffer this charge. Also, any character that is wearing a Hawaiian shirt or T-shirt without body armor or cloak suffers this charge.

dunce => BOOL (default: false)

Determines whether the character suffers from the "dunce" surcharge. This applies to any character who is wearing a dunce cap. Whoops, should price ID those conical hats to filter for cornuthaums.

angry => BOOL (default: false)

Determines whether the character suffers from the "angry shopkeeper" surcharge. If the shopkeeper is attacking you, you'll probably want to set this one to true. Warning: if you try to sell an item to an angry shopkeeper, they'll just take it. That doesn't help much for identification.

quan => INT (default: 1)

How many items in the stack you're buying/selling. Most people try to identify with only one item, but this is available if you take the path less trodden.

priceid_buy PARAMHASH

Same as priceid except with a default of in => 'buy'.

priceid_sell PARAMHASH

Same as priceid except with a default of in => 'sell'.

priceid_base PARAMHASH

Same as priceid, which does have a default of in => 'base', but I cannot abide inconsistency.

EXAMPLES

Selling

You are selling an unknown ring and want to know what kind it may be. We have no unusual surcharges (and charisma is not needed when sell IDing).

    "Wonotobo offers 75 gold pieces for your clay ring.  Sell it?";

    priceid(in => 'sell',
            type => 'ring',
            amount => 75);
    => ('aggravate monster', 'cold resistance', 'fire
         resistance', 'free action', 'gain constitution', 'gain
         strength', 'increase accuracy', 'increase damage',
        'invisibility', 'levitation', 'poison resistance',
        'regeneration', 'searching', 'see invisible', 'shock
         resistance', 'slow digestion', 'teleportation')

Well, that's an awful lot of hits. Let's just look at the actual base prices that we get back.

    priceid(in => 'sell',
            type => 'ring',
            amount => 75,
            out => 'base');
    => (150, 200)

Ah. So we are at one of those "could be two possible categories" sweet spots. So we continue dropping the ring until we get a different price (which will reflect a change in whether we get a random surcharge).

    "Wonotobo offers 100 gold pieces for your clay ring.  Sell it?";

    priceid(in => 'sell',
            type => 'ring',
            amount => 100)
    => ('fire resistance', 'free action', 'levitation',
        'regeneration', 'searching', 'slow digestion',
        'teleportation')
Buying with mods

This game has not been going well. This wizard has had his cloak of magic resistance stolen by a nymph. The conical hat that he hurriedly put on turned out to be a dunce cap. Furthermore, nothing is covering his cursed Hawaiian shirt. He has just found a store and is pricing the items in it. He picks up a wand...

    "For you, most gracious sir; only 888 for this curved wand.";

    priceid(charisma => 9,
            in => 'buy',
            type => 'wand',
            dunce => 1,
            tourist => 1,
            amount => 888)
    => ('death', 'wishing')

He quickly zaps the wand, wishes for a cockatrice corpse with which to kill the shopkeeper, and turns to stone... oops, no gloves!

TODO

User-defined item tables

This would be mostly useful for Slash'EM and Sporkhack. Does Slash'EM even use the same cost calculations? Probably.

Ignore trivial identifications

Yes, we know that an unlabeled scroll is blank paper, and clear potion is water. We usually don't need the module to report these.

How much would this item cost?

This is already implemented, somewhat, it's just hidden in priceid_buy and priceid_sell. It should be factored out and made into API.

Parse the actual NetHack output

It'd be great if all we had to do is hand in the string

    Wonotobo offers 30 gold pieces for your scroll labeled KIRJE.  Sell it?

and have the module figure out the relevant bits. Also, possibly, the entire screen (so that charisma could be discerned).

Ignore items I already know

You could pass in a list of items that you've already identified or ruled out, and the module would not include those in the list of possibilities.

SEE ALSO

Clippy

http://nethack.roy.org/clippy/clippy.pl

HiSPeed's NetHack Helper

http://nethack.holics.at/nh-helper-public/nh-helper.html

NetHack Object Identification Spoiler

http://www.chiark.greenend.org.uk/~damerell/games/nhid.html

Interhack

http://taeb.github.io/interhack/

AUTHOR

Shawn M Moore <code@sartak.org>

COPYRIGHT AND LICENSE

This software is copyright (c) 2014 by Shawn M Moore.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.