Rascal

by Tara McGrew

Download Source Text (ZIP)

itemdef.zil

"Item definitions and lookup tables"

<CONSTANT ITEMKIND-FOOD 1>
<CONSTANT ITEMKIND-TREASURE 2>
<CONSTANT ITEMKIND-WEAPON 3>
<CONSTANT ITEMKIND-POTION 4>
<CONSTANT ITEMKIND-GOLD 5>
<CONSTANT ITEMKIND-KEY 6>
<CONSTANT ITEMKIND-LOCKEDDOOR 7>
<CONSTANT ITEMKIND-SHRINE 8>
<CONSTANT ITEMKIND-COFFER 9>
<CONSTANT ITEMKIND-ALTAR 10>
<CONSTANT ITEMKIND-COUNT 10>

<CONSTANT COFFER-TYPE-COFFER 1>
<CONSTANT COFFER-TYPE-MIMICK 2>

<CONSTANT LOCK-GOLDEN 1>
<CONSTANT LOCK-SILVER 2>
<CONSTANT LOCK-BRONZE 3>
<CONSTANT LOCK-COPPER 4>
<CONSTANT LOCK-NICKEL 5>
<CONSTANT LOCK-COBALT 6>
<CONSTANT LOCK-TYPE-COUNT 6>

<CONSTANT WEAPON-DAGGER 1>
<CONSTANT WEAPON-KATANA 2>
<CONSTANT WEAPON-WARAXE 3>
<CONSTANT WEAPON-SCYTHE 4>
<CONSTANT WEAPON-CUDGEL 5>
<CONSTANT WEAPON-HAMMER 6>
<CONSTANT WEAPON-COUNT 6>

<CONSTANT POTION-MUSCLE 1>
<CONSTANT POTION-HEALTH 2>
<CONSTANT POTION-HIDING 3>
<CONSTANT POTION-POISON 4>
<CONSTANT POTION-VISION 5>
<CONSTANT POTION-MOTION 6>
<CONSTANT POTION-SHADOW 7>
<CONSTANT POTION-METTLE 8>
<CONSTANT POTION-TORPOR 9>
<CONSTANT POTION-HUSTLE 10>
<CONSTANT POTION-RAGING 11>
<CONSTANT POTION-ARMOUR 12>
<CONSTANT POTION-VIGOUR 13>
<CONSTANT POTION-EXCESS 14>
<CONSTANT POTION-ALLURE 15>
<CONSTANT POTION-SCHEMA 16>
<CONSTANT POTION-ACUMEN 17>
<CONSTANT POTION-TYPE-COUNT 17>

<CONSTANT POTCOLOR-ARGENT 1>
<CONSTANT POTCOLOR-BLUISH 2>
<CONSTANT POTCOLOR-MAROON 3>
<CONSTANT POTCOLOR-VIOLET 4>
<CONSTANT POTCOLOR-ORANGE 5>
<CONSTANT POTCOLOR-YELLOW 6>
<CONSTANT POTCOLOR-INDIGO 7>
<CONSTANT POTCOLOR-SALMON 8>
<CONSTANT POTCOLOR-AUBURN 9>
<CONSTANT POTCOLOR-SIENNA 10>
<CONSTANT POTION-COLOR-COUNT 10>

<CONSTANT ALTAR-CATEGORY-NONE 0>
<CONSTANT ALTAR-CATEGORY-COMBAT 1>
<CONSTANT ALTAR-CATEGORY-HEALTH 2>
<CONSTANT ALTAR-CATEGORY-WEALTH 3>
<CONSTANT ALTAR-CATEGORY-WISDOM 4>

<CONSTANT FOOD-BANANA 1>
<CONSTANT FOOD-CHEESE 2>
<CONSTANT FOOD-GRAPES 3>
<CONSTANT FOOD-MUFFIN 4>
<CONSTANT FOOD-TURKEY 5>
<CONSTANT FOOD-CARROT 6>
<CONSTANT FOOD-CAVIAR 7>
<CONSTANT FOOD-TYPE-COUNT 7>

<CONSTANT TREASURE-AMULET 1>
<CONSTANT TREASURE-SCARAB 2>
<CONSTANT TREASURE-GOBLET 3>
<CONSTANT TREASURE-IOLITE 4>
<CONSTANT TREASURE-GARNET 5>
<CONSTANT TREASURE-JASPER 6>
<CONSTANT TREASURE-ZIRCON 7>
<CONSTANT TREASURE-POSTER 8>
<CONSTANT TREASURE-TROPHY 9>
<CONSTANT TREASURE-COUNT 9>

;"Prints a weapon type code as its display name.

Args:
  TYPE: Weapon type code (WEAPON-*).

Returns:
  T."

<ROUTINE PRINT-WEAPON-NAME (TYPE)
    <COND (<==? .TYPE ,WEAPON-DAGGER> <TELL "dagger">)
          (<==? .TYPE ,WEAPON-KATANA> <TELL "katana">)
          (<==? .TYPE ,WEAPON-WARAXE> <TELL "waraxe">)
          (<==? .TYPE ,WEAPON-SCYTHE> <TELL "scythe">)
          (<==? .TYPE ,WEAPON-CUDGEL> <TELL "cudgel">)
          (<==? .TYPE ,WEAPON-HAMMER> <TELL "hammer">)
          (ELSE <TELL "weapon">)>
    <RTRUE>>

;"Returns the integer square root of N.

Args:
  N: Non-negative integer.

Returns:
  Greatest integer R such that R*R <= N."

<ROUTINE INTEGER-SQRT (N "AUX" ROOT NEXT)
    <COND (<L=? .N 0> <RETURN 0>)>
    <SET ROOT 0>
    <REPEAT ()
        <SET NEXT <+ .ROOT 1>>
        <COND (<G? <* .NEXT .NEXT> .N> <RETURN .ROOT>)>
        <SET ROOT .NEXT>>>

;"Rounds VALUE * PCT / 100 upward.

Args:
  VALUE: Non-negative integer value.
  PCT: Percentage multiplier.

Returns:
  Rounded-up percentage amount."

<ROUTINE PERCENT-CEILING (VALUE PCT)
    <COND (<L=? .VALUE 0> 0)
          (ELSE </ <+ <* .VALUE .PCT> 99> 100>)>>

;"Maps a weapon type code to its power bonus.

Args:
  TYPE: Weapon type code (WEAPON-*).

Returns:
  Signed power bonus."

<ROUTINE WEAPON-POWER-BONUS (TYPE)
    <COND (<==? .TYPE ,WEAPON-DAGGER> ,WEAPON-POWER-BONUS-DAGGER)
          (<==? .TYPE ,WEAPON-KATANA> ,WEAPON-POWER-BONUS-KATANA)
          (<==? .TYPE ,WEAPON-WARAXE> ,WEAPON-POWER-BONUS-WARAXE)
          (<==? .TYPE ,WEAPON-SCYTHE> ,WEAPON-POWER-BONUS-SCYTHE)
          (<==? .TYPE ,WEAPON-CUDGEL> ,WEAPON-POWER-BONUS-CUDGEL)
          (<==? .TYPE ,WEAPON-HAMMER> ,WEAPON-POWER-BONUS-HAMMER)
          (ELSE 0)>>

;"Maps a weapon type code to its minimum base-damage percentage.

Args:
  TYPE: Weapon type code (WEAPON-*).

Returns:
  Percentage multiplier (0..100+)."

<ROUTINE WEAPON-MIN-PCT (TYPE)
    <COND (<==? .TYPE ,WEAPON-DAGGER> ,WEAPON-MIN-PCT-DAGGER)
          (<==? .TYPE ,WEAPON-KATANA> ,WEAPON-MIN-PCT-KATANA)
          (<==? .TYPE ,WEAPON-WARAXE> ,WEAPON-MIN-PCT-WARAXE)
          (<==? .TYPE ,WEAPON-SCYTHE> ,WEAPON-MIN-PCT-SCYTHE)
          (<==? .TYPE ,WEAPON-CUDGEL> ,WEAPON-MIN-PCT-CUDGEL)
          (<==? .TYPE ,WEAPON-HAMMER> ,WEAPON-MIN-PCT-HAMMER)
          (ELSE 75)>>

;"Maps a weapon type code to its maximum base-damage percentage.

Args:
  TYPE: Weapon type code (WEAPON-*).

Returns:
  Percentage multiplier (0..100+)."

<ROUTINE WEAPON-MAX-PCT (TYPE)
    <COND (<==? .TYPE ,WEAPON-DAGGER> ,WEAPON-MAX-PCT-DAGGER)
          (<==? .TYPE ,WEAPON-KATANA> ,WEAPON-MAX-PCT-KATANA)
          (<==? .TYPE ,WEAPON-WARAXE> ,WEAPON-MAX-PCT-WARAXE)
          (<==? .TYPE ,WEAPON-SCYTHE> ,WEAPON-MAX-PCT-SCYTHE)
          (<==? .TYPE ,WEAPON-CUDGEL> ,WEAPON-MAX-PCT-CUDGEL)
          (<==? .TYPE ,WEAPON-HAMMER> ,WEAPON-MAX-PCT-HAMMER)
          (ELSE 125)>>

;"Maps a weapon type code to its crit chance.

Args:
  TYPE: Weapon type code (WEAPON-*).

Returns:
  Crit chance percentage (0..100)."

<ROUTINE WEAPON-CRIT-PCT (TYPE)
    <COND (<==? .TYPE ,WEAPON-DAGGER> ,WEAPON-CRIT-PCT-DAGGER)
          (<==? .TYPE ,WEAPON-KATANA> ,WEAPON-CRIT-PCT-KATANA)
          (<==? .TYPE ,WEAPON-WARAXE> ,WEAPON-CRIT-PCT-WARAXE)
          (<==? .TYPE ,WEAPON-SCYTHE> ,WEAPON-CRIT-PCT-SCYTHE)
          (<==? .TYPE ,WEAPON-CUDGEL> ,WEAPON-CRIT-PCT-CUDGEL)
          (<==? .TYPE ,WEAPON-HAMMER> ,WEAPON-CRIT-PCT-HAMMER)
          (ELSE 10)>>

;"Maps a weapon type code to its crit bonus percentage.

Args:
  TYPE: Weapon type code (WEAPON-*).

Returns:
  Percentage multiplier (0..100+)."

<ROUTINE WEAPON-CRIT-BONUS-PCT (TYPE)
    <COND (<==? .TYPE ,WEAPON-DAGGER> ,WEAPON-CRIT-BONUS-PCT-DAGGER)
          (<==? .TYPE ,WEAPON-KATANA> ,WEAPON-CRIT-BONUS-PCT-KATANA)
          (<==? .TYPE ,WEAPON-WARAXE> ,WEAPON-CRIT-BONUS-PCT-WARAXE)
          (<==? .TYPE ,WEAPON-SCYTHE> ,WEAPON-CRIT-BONUS-PCT-SCYTHE)
          (<==? .TYPE ,WEAPON-CUDGEL> ,WEAPON-CRIT-BONUS-PCT-CUDGEL)
          (<==? .TYPE ,WEAPON-HAMMER> ,WEAPON-CRIT-BONUS-PCT-HAMMER)
          (ELSE 50)>>

;"Calculates the enchantment damage bonus used in weapon power.

Args:
  ENCH: Weapon enchantment.

Returns:
  Signed damage bonus."

<ROUTINE WEAPON-ENCHANT-DMG-BONUS (ENCH)
    <COND (<L=? .ENCH 0> .ENCH)
      (ELSE <INTEGER-SQRT <* .ENCH 3>>)>>

;"Calculates the minimum strength needed to wield a weapon properly.

Args:
  LVL: Weapon level.
  ENCH: Weapon enchantment.

Returns:
  Strength requirement (>= 1)."

<ROUTINE WEAPON-REQUIRED-STR (LVL ENCH "AUX" REQ)
    <SET REQ <- .LVL .ENCH>>
    <COND (<L=? .REQ 1> 1)
          (ELSE .REQ)>>

;"Calculates the weapon mastery bonus for a given strength.

Args:
  STR: Player strength.
  LVL: Weapon level.
  ENCH: Weapon enchantment.

Returns:
  Non-negative mastery bonus."

<ROUTINE WEAPON-MASTERY (STR LVL ENCH "AUX" EXCESS)
    <COND (<L? .STR <WEAPON-REQUIRED-STR .LVL .ENCH>> <RETURN 0>)>
    <SET EXCESS <- .STR .LVL>>
    <COND (<L? .EXCESS 0> <RETURN 0>)>
  <SET EXCESS </ .EXCESS 2>>
  <INTEGER-SQRT .EXCESS>>

;"Calculates the intermediate power value for a weapon.

Args:
  TYPE: Weapon type code (WEAPON-*).
  LVL: Weapon level.
  ENCH: Weapon enchantment.
  STR: Player strength.

Returns:
  Power value used by weapon damage rolls."

<ROUTINE WEAPON-POWER (TYPE LVL ENCH STR "AUX" POWER)
    <SET POWER
         <+ 1
            <+ .LVL
               <+ <WEAPON-ENCHANT-DMG-BONUS .ENCH>
                  <+ <WEAPON-POWER-BONUS .TYPE>
                     <WEAPON-MASTERY .STR .LVL .ENCH>>>>>>
    <COND (<L=? .POWER 1> 1)
          (ELSE .POWER)>>

;"Calculates the minimum base damage for a weapon.

Args:
  TYPE: Weapon type code (WEAPON-*).
  LVL: Weapon level.
  ENCH: Weapon enchantment.
  STR: Player strength.

Returns:
  Minimum base-damage roll (>= 1)."

<ROUTINE WEAPON-MIN-DMG (TYPE LVL ENCH STR "AUX" POWER DMG)
    <SET POWER <WEAPON-POWER .TYPE .LVL .ENCH .STR>>
    <SET DMG <PERCENT-CEILING .POWER <WEAPON-MIN-PCT .TYPE>>>
    <COND (<L=? .DMG 1> 1)
          (ELSE .DMG)>>

;"Calculates the maximum base damage for a weapon.

Args:
  TYPE: Weapon type code (WEAPON-*).
  LVL: Weapon level.
  ENCH: Weapon enchantment.
  STR: Player strength.

Returns:
  Maximum base-damage roll (>= minimum roll)."

<ROUTINE WEAPON-MAX-DMG (TYPE LVL ENCH STR "AUX" MIN POWER DMG)
    <SET MIN <WEAPON-MIN-DMG .TYPE .LVL .ENCH .STR>>
    <SET POWER <WEAPON-POWER .TYPE .LVL .ENCH .STR>>
    <SET DMG <PERCENT-CEILING .POWER <WEAPON-MAX-PCT .TYPE>>>
    <COND (<L? .DMG .MIN> .MIN)
          (ELSE .DMG)>>

;"Calculates the critical-hit bonus damage for a weapon.

Args:
  TYPE: Weapon type code (WEAPON-*).
  LVL: Weapon level.
  ENCH: Weapon enchantment.
  STR: Player strength.

Returns:
  Additional critical-hit damage (>= 1)."

<ROUTINE WEAPON-CRIT-BONUS-DMG (TYPE LVL ENCH STR "AUX" POWER DMG)
    <SET POWER <WEAPON-POWER .TYPE .LVL .ENCH .STR>>
    <SET DMG <PERCENT-CEILING .POWER <WEAPON-CRIT-BONUS-PCT .TYPE>>>
    <COND (<L=? .DMG 1> 1)
          (ELSE .DMG)>>

;"Calculates the expected base damage of a weapon.

Args:
  TYPE: Weapon type code (WEAPON-*).
  LVL: Weapon level.
  ENCH: Weapon enchantment.

Returns:
  Average base damage, ignoring crits."

<ROUTINE WEAPON-AVERAGE-BASE-DMG (TYPE LVL ENCH "AUX" MIN MAX)
    <SET MIN <WEAPON-MIN-DMG .TYPE .LVL .ENCH .LVL>>
    <SET MAX <WEAPON-MAX-DMG .TYPE .LVL .ENCH .LVL>>
  <SET MAX </ <+ .MIN .MAX> 2>>
  .MAX>

;"Prints a food type code as its display name.

Args:
  TYPE: Food type code (FOOD-*).

Returns:
  T."

<ROUTINE PRINT-FOOD-NAME (TYPE)
    <COND (<==? .TYPE ,FOOD-BANANA> <TELL "banana">)
          (<==? .TYPE ,FOOD-CHEESE> <TELL "cheese">)
          (<==? .TYPE ,FOOD-GRAPES> <TELL "grapes">)
          (<==? .TYPE ,FOOD-MUFFIN> <TELL "muffin">)
          (<==? .TYPE ,FOOD-TURKEY> <TELL "turkey">)
          (<==? .TYPE ,FOOD-CARROT> <TELL "carrot">)
          (<==? .TYPE ,FOOD-CAVIAR> <TELL "caviar">)
          (ELSE <TELL "food">)>
    <RTRUE>>

;"Maps a food type code to its map sprite.

Args:
  TYPE: Food type code (FOOD-*).

Returns:
  ZSCII tile constant (TILE-*)."

<ROUTINE FOOD-TILE-FOR-TYPE (TYPE)
    <COND (<==? .TYPE ,FOOD-BANANA> ,TILE-BANANA)
          (<==? .TYPE ,FOOD-CHEESE> ,TILE-CHEESE)
          (<==? .TYPE ,FOOD-GRAPES> ,TILE-GRAPES)
          (<==? .TYPE ,FOOD-MUFFIN> ,TILE-MUFFIN)
          (<==? .TYPE ,FOOD-TURKEY> ,TILE-TURKEY)
          (<==? .TYPE ,FOOD-CARROT> ,TILE-CARROT)
          (<==? .TYPE ,FOOD-CAVIAR> ,TILE-CAVIAR)
          (ELSE ,TILE-MUFFIN)>>

;"Maps a food type code to its healing amount.

Args:
  TYPE: Food type code (FOOD-*).

Returns:
  Positive integer healing amount (HP)."

<ROUTINE FOOD-HEAL-AMT (TYPE)
    <COND (<==? .TYPE ,FOOD-BANANA> ,FOOD-HEAL-AMT-BANANA)
          (<==? .TYPE ,FOOD-CHEESE> ,FOOD-HEAL-AMT-CHEESE)
          (<==? .TYPE ,FOOD-GRAPES> ,FOOD-HEAL-AMT-GRAPES)
          (<==? .TYPE ,FOOD-MUFFIN> ,FOOD-HEAL-AMT-MUFFIN)
          (<==? .TYPE ,FOOD-TURKEY> ,FOOD-HEAL-AMT-TURKEY)
          (<==? .TYPE ,FOOD-CARROT> ,FOOD-HEAL-AMT-CARROT)
          (<==? .TYPE ,FOOD-CAVIAR> ,FOOD-HEAL-AMT-CAVIAR)
          (ELSE 2)>>

;"Maps a food type code to the trader buy price.

Args:
  TYPE: Food type code (FOOD-*).

Returns:
  Gold value as a positive integer."

<ROUTINE FOOD-VALUE (TYPE)
    <COND (<==? .TYPE ,FOOD-CARROT> 100)
          (ELSE <+ 10 <* 10 <FOOD-HEAL-AMT .TYPE>>>)>>

;"Prints a potion effect/type code as its display name.

Args:
  TYPE: Potion type code (POTION-*).

Returns:
  T."

<ROUTINE PRINT-POTION-EFFECT-NAME (TYPE)
    <COND (<==? .TYPE ,POTION-MUSCLE> <TELL "muscle">)
          (<==? .TYPE ,POTION-HEALTH> <TELL "health">)
          (<==? .TYPE ,POTION-HIDING> <TELL "hiding">)
          (<==? .TYPE ,POTION-POISON> <TELL "poison">)
          (<==? .TYPE ,POTION-VISION> <TELL "vision">)
          (<==? .TYPE ,POTION-MOTION> <TELL "motion">)
          (<==? .TYPE ,POTION-SHADOW> <TELL "shadow">)
          (<==? .TYPE ,POTION-METTLE> <TELL "mettle">)
      (<==? .TYPE ,POTION-TORPOR> <TELL "torpor">)
      (<==? .TYPE ,POTION-HUSTLE> <TELL "hustle">)
          (<==? .TYPE ,POTION-RAGING> <TELL "raging">)
          (<==? .TYPE ,POTION-ARMOUR> <TELL "armour">)
          (<==? .TYPE ,POTION-VIGOUR> <TELL "vigour">)
          (<==? .TYPE ,POTION-EXCESS> <TELL "excess">)
          (<==? .TYPE ,POTION-ALLURE> <TELL "allure">)
          (<==? .TYPE ,POTION-SCHEMA> <TELL "schema">)
          (<==? .TYPE ,POTION-ACUMEN> <TELL "acumen">)
          (ELSE <TELL "potion">)>
    <RTRUE>>

<ROUTINE PRINT-POTION-TYPE-NAME (TYPE)
    <TELL "potion of ">
    <PRINT-POTION-EFFECT-NAME .TYPE>
    <RTRUE>>

;"Prints a potion effect/type code as its pluralized display name.

Args:
  TYPE: Potion type code (POTION-*).

Returns:
  T."

<ROUTINE PRINT-POTION-PLURAL-TYPE-NAME (TYPE)
    <TELL "potions of ">
    <PRINT-POTION-EFFECT-NAME .TYPE>
    <RTRUE>>

;"Prints a potion color code as its (concealed) display name.

Args:
  COLOR: Potion color code (POTCOLOR-*).

Returns:
  T."

<ROUTINE PRINT-POTION-COLOR-ADJ (COLOR)
    <COND (<==? .COLOR ,POTCOLOR-ARGENT> <TELL "argent">)
          (<==? .COLOR ,POTCOLOR-BLUISH> <TELL "bluish">)
          (<==? .COLOR ,POTCOLOR-MAROON> <TELL "maroon">)
          (<==? .COLOR ,POTCOLOR-VIOLET> <TELL "violet">)
          (<==? .COLOR ,POTCOLOR-ORANGE> <TELL "orange">)
          (<==? .COLOR ,POTCOLOR-YELLOW> <TELL "yellow">)
          (<==? .COLOR ,POTCOLOR-INDIGO> <TELL "indigo">)
          (<==? .COLOR ,POTCOLOR-SALMON> <TELL "salmon">)
      (<==? .COLOR ,POTCOLOR-AUBURN> <TELL "auburn">)
      (<==? .COLOR ,POTCOLOR-SIENNA> <TELL "sienna">)
          (ELSE <TELL "colored">)>
    <RTRUE>>

<ROUTINE PRINT-POTION-COLOR-NAME (COLOR)
    <PRINT-POTION-COLOR-ADJ .COLOR>
    <TELL " potion">
    <RTRUE>>

;"Prints a potion color code as the color adjective only.

Args:
  COLOR: Potion color code (POTCOLOR-*).

Returns:
  T."
<ROUTINE PRINT-POTION-BARE-COLOR-NAME (COLOR)
    <PRINT-POTION-COLOR-ADJ .COLOR>
    <RTRUE>>

;"Prints the player-facing name for a potion of the given color.

Before a color is discovered, this returns the concealed color name. After it
is discovered, it returns the underlying potion type name.

Args:
  COLOR: Potion color code (POTCOLOR-*).

Returns:
  T."

<ADD-TELL-TOKENS
    POTION-TYPE-NAME * <PRINT-POTION-TYPE-NAME .X>
    POTION-PLURAL-TYPE-NAME * <PRINT-POTION-PLURAL-TYPE-NAME .X>
    POTION-COLOR-NAME * <PRINT-POTION-COLOR-NAME .X>
    POTION-BARE-COLOR-NAME * <PRINT-POTION-BARE-COLOR-NAME .X>
    POTION-DISPLAY-NAME * <PRINT-POTION-DISPLAY-NAME .X>>

<ROUTINE PRINT-POTION-DISPLAY-NAME (COLOR "AUX" TYPE)
    <COND (<OR <L? .COLOR 1> <G? .COLOR ,POTION-TYPE-COUNT>>
           <TELL "potion">
           <RTRUE>)>
    ;"Fixed potions (ITID > POTION-COLOR-COUNT) always show their type name."
    <COND (<G? .COLOR ,POTION-COLOR-COUNT>
           <PRINT-POTION-TYPE-NAME .COLOR>
           <RTRUE>)>
    <COND (<G? <GETB ,POTION-DISCOVERED <- .COLOR 1>> 0>
           <SET TYPE <GETB ,POTION-TYPE-FOR-COLOR <- .COLOR 1>>>
           <PRINT-POTION-TYPE-NAME .TYPE>)
          (ELSE <PRINT-POTION-COLOR-NAME .COLOR>)>
    <RTRUE>>

;"Returns the correct indefinite article (a vs an) for the player-facing
  potion name of the given color.

We only need special handling for undiscovered color names like argent potion;
once discovered, the name becomes potion of ...

Args:
  COLOR: Potion color code (POTCOLOR-*).

Returns:
  The string a or an."

<ROUTINE POTION-ARTICLE (COLOR)
    ;"Fixed potions always start with 'a' (a potion of ...)."
    <COND (<G? .COLOR ,POTION-COLOR-COUNT> <RETURN "a">)>
    <COND (<OR <L? .COLOR 1> <G? .COLOR ,POTION-COLOR-COUNT>> <RETURN "a">)>
    <COND (<G? <GETB ,POTION-DISCOVERED <- .COLOR 1>> 0> <RETURN "a">)>
    <COND (<==? .COLOR
                ,POTCOLOR-ARGENT
                ,POTCOLOR-AUBURN
                ,POTCOLOR-ORANGE
                ,POTCOLOR-INDIGO>
           "an")
          (ELSE "a")>>

;"Prints a treasure ID as its display name.

Args:
  ID: Treasure ID (TREASURE-*).

Returns:
  T."

<ROUTINE PRINT-TREASURE-NAME (ID)
    <COND (<==? .ID ,TREASURE-AMULET> <TELL "amulet">)
          (<==? .ID ,TREASURE-SCARAB> <TELL "scarab">)
          (<==? .ID ,TREASURE-GOBLET> <TELL "goblet">)
          (<==? .ID ,TREASURE-IOLITE> <TELL "iolite">)
          (<==? .ID ,TREASURE-GARNET> <TELL "garnet">)
          (<==? .ID ,TREASURE-JASPER> <TELL "jasper">)
          (<==? .ID ,TREASURE-ZIRCON> <TELL "zircon">)
          (<==? .ID ,TREASURE-POSTER> <TELL "poster">)
          (<==? .ID ,TREASURE-TROPHY> <TELL "Trophy of Scryra">)
          (ELSE <TELL "treasure">)>
    <RTRUE>>

;"Returns the correct indefinite article (a vs an) for a treasure.

Args:
  ID: Treasure ID (TREASURE-*).

Returns:
  The string a or an."

<ROUTINE TREASURE-ARTICLE (ID)
    <COND (<==? .ID ,TREASURE-AMULET ,TREASURE-IOLITE> "an")
          (ELSE "a")>>

;"Maps a treasure ID to the trader buy price.

Args:
  ID: Treasure ID (TREASURE-*).

Returns:
  Gold value as a positive integer."

<ROUTINE TREASURE-VALUE (ID)
    <COND (<==? .ID ,TREASURE-AMULET> 180)
          (<==? .ID ,TREASURE-SCARAB> 200)
          (<==? .ID ,TREASURE-GOBLET> 250)
          (<==? .ID ,TREASURE-IOLITE> 300)
          (<==? .ID ,TREASURE-GARNET> 400)
          (<==? .ID ,TREASURE-JASPER> 600)
          (<==? .ID ,TREASURE-ZIRCON> 1000)
          (<==? .ID ,TREASURE-POSTER> <COND (,EXPERT-MODE? 50) (ELSE 1500)>)
          (<==? .ID ,TREASURE-TROPHY> 5000)
          (ELSE 50)>>

;"Prints a key ID as its display name.

Args:
  LOCKTYPE: Key ID (LOCKTYPE-*).

Returns:
  T."
<ROUTINE PRINT-KEY-NAME (LOCKTYPE)
    <COND (<==? .LOCKTYPE ,LOCK-GOLDEN> <TELL "golden key">)
          (<==? .LOCKTYPE ,LOCK-SILVER> <TELL "silver key">)
          (<==? .LOCKTYPE ,LOCK-BRONZE> <TELL "bronze key">)
          (<==? .LOCKTYPE ,LOCK-COPPER> <TELL "copper key">)
          (<==? .LOCKTYPE ,LOCK-NICKEL> <TELL "nickel key">)
          (<==? .LOCKTYPE ,LOCK-COBALT> <TELL "cobalt key">)
          (ELSE <TELL "key">)>
    <RTRUE>>

;"Maps a key ID to its metal adjective.

Args:
  LOCKTYPE: Key ID (LOCKTYPE-*).

Returns:
  Adjective string like \"golden\"."
<ROUTINE KEY-BARE-METAL-DESC (LOCKTYPE)
    <COND (<==? .LOCKTYPE ,LOCK-GOLDEN> "golden")
          (<==? .LOCKTYPE ,LOCK-SILVER> "silver")
          (<==? .LOCKTYPE ,LOCK-BRONZE> "bronze")
          (<==? .LOCKTYPE ,LOCK-COPPER> "copper")
          (<==? .LOCKTYPE ,LOCK-NICKEL> "nickel")
          (<==? .LOCKTYPE ,LOCK-COBALT> "cobalt")
          (ELSE "metal")>>

<ROUTINE KEY-VALUE (LOCKTYPE)
    <COND (<==? .LOCKTYPE ,LOCK-GOLDEN ,LOCK-SILVER> 150)
          (<==? .LOCKTYPE ,LOCK-BRONZE ,LOCK-COPPER> 100)
          (<==? .LOCKTYPE ,LOCK-NICKEL ,LOCK-COBALT> 50)
          (ELSE 50)>>

<ADD-TELL-TOKENS
    WEAPON-NAME *   <PRINT-WEAPON-NAME .X>
    FOOD-NAME *     <PRINT-FOOD-NAME .X>
    TREASURE-NAME * <PRINT-TREASURE-NAME .X>
    KEY-NAME *      <PRINT-KEY-NAME .X>>


;"Trader buy price for any potion (same regardless of type/color)."

<CONSTANT POTION-VALUE 150>

;"Maps a weapon type+level+enchantment to the trader buy price.

Weapon values scale with their level.

Args:
    TYPE: Weapon type code (WEAPON-*).
    LVL: Weapon level.
    ENCH: Enchantment level.

Returns:
  Gold value as a positive integer."

<ROUTINE WEAPON-VALUE (TYPE LVL ENCH "AUX" BASE)
    <SET BASE <WEAPON-AVERAGE-BASE-DMG .TYPE 1 0>>
    <SET BASE <+ 1 <+ <* 2 .BASE> <+ <* 4 .LVL> <* 2 .ENCH>>>>>
    .BASE>