diff urogue/trader.c @ 256:c495a4f288c6

Import UltraRogue from the Roguelike Restoration Project (r1490)
author John "Elwin" Edwards
date Tue, 31 Jan 2017 19:56:04 -0500
parents
children 0250220d8cdd
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/trader.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,808 @@
+/*
+    trader.c - Anything to do with trading posts
+     
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
+    All rights reserved.
+
+    Based on "Rogue: Exploring the Dungeons of Doom"
+    Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include "rogue.h"
+
+#define EFFECTIVE_PURSE ((player.t_ctype==C_PALADIN)?(9 * purse / 10) : purse)
+
+/*
+    do_post()
+        Buy and sell things in a trading post
+*/
+
+void
+display_postinfo(void)
+{
+    wclear(hw);
+    wstandout(hw);
+    mvwaddstr(hw, 0, COLS / 2 - 30,
+        "Welcome to Friendly Fiend's Flea Market" );
+    wstandend(hw);
+    wclrtoeol(hw);
+    trans_line();   
+}
+
+void
+do_post(void)
+{
+    int bad_letter = FALSE;
+
+    player.t_trans = 0;
+
+    for (;;)
+    {
+        if (!open_market())
+            return;
+
+        display_postinfo();
+
+        if (bad_letter)
+        {
+            bad_letter = FALSE;
+            wstandout(hw);
+            mvwaddstr(hw, 7, 0, "Type 'i' or 'I' to inventory, "
+                                "'l' to leave, 'b' to buy, or 's' to sell");
+            wstandend(hw);
+        }
+
+        mvwaddstr(hw, 6, 0, "Do you wish to buy, sell, inventory, or leave?");
+        wrefresh(hw);
+
+        switch(readcharw(hw))
+        {
+            case 'b':
+                mvwaddstr(hw, 7, 0,
+                    "Lets go into the buying section of the store...");
+                touchwin(hw);
+                wrefresh(hw);
+                buy_it('\0', ISNORMAL);
+                break;
+
+            case 's':
+                mvwaddstr(hw, 7, 0,
+                    "Lets go into the selling section of the store...");
+                touchwin(hw);
+                wrefresh(hw);
+                sell_it();
+                break;
+
+            case 'i':
+                inventory(pack, '*');
+                break;
+
+            case 'I':
+                wclear(hw);
+                wrefresh(hw);
+                inventory(pack, 0);
+                msg(" ");
+                msg("");
+                break;
+
+            case 'l':
+                wclear(hw);
+                wrefresh(hw);
+                return;
+
+            default:
+                bad_letter = TRUE;
+                break;
+        }
+    }
+}
+
+void
+buy_it(char itemtype, int flags)
+{
+    int i;
+    int blessed = flags & ISBLESSED;
+    int cursed = flags & ISCURSED;
+    int is_spell = flags & SCR_MAGIC;
+    int array_size; /* # of items within type */
+    int which_type = 0; /* Which type to buy */
+    int which_one;  /* Which one within type */
+    int plus_or_minus = 0;  /* for magic items */
+    const struct magic_item   *magic_array = NULL;
+    struct linked_list  *item;
+    struct object *obj;
+    char buf[2 * LINELEN];
+
+buy_more:
+
+    display_postinfo();
+
+    do
+    {
+        array_size = 0;
+
+        if (itemtype == '\0')
+        {
+            mpos = 0;
+	    wmove(hw,10,0);
+	    wclrtoeol(hw);
+            mvwaddstr(hw, 11, 0, "WHAT\tTYPE\n! Potion\n? Scroll\n"
+                                 "= Ring\n/ Stick\n] Armor\n) Weapon\n: Food");
+
+            if (wizard)
+                mvwaddstr(hw, 19, 0, ", Artifact");
+
+            mvwaddstr(hw, 9, 0, "What type of item do you want? ");
+            wclrtoeol(hw);
+            touchwin(hw);
+            wrefresh(hw);
+            itemtype = readcharw(hw);
+        }
+
+        switch(itemtype)
+        {
+            case POTION:
+                which_type = TYP_POTION;
+                array_size = maxpotions;
+                magic_array = p_magic;
+                break;
+
+            case SCROLL:
+                which_type = TYP_SCROLL;
+                array_size = maxscrolls;
+                magic_array = s_magic;
+                break;
+
+            case FOOD:
+                which_type = TYP_FOOD;
+                array_size = maxfoods;
+                magic_array = fd_data;
+                break;
+
+            case WEAPON:
+                which_type = TYP_WEAPON;
+                array_size = maxweapons;
+                break;
+
+            case ARMOR:
+                which_type = TYP_ARMOR;
+                array_size = maxarmors;
+                break;
+
+            case RING:
+                which_type = TYP_RING;
+                array_size = maxrings;
+                magic_array = r_magic;
+                break;
+
+            case STICK:
+                which_type = TYP_STICK;
+                array_size = maxsticks;
+                magic_array = ws_magic;
+                break;
+
+            case ARTIFACT:
+                if (!wizard)
+                {
+                    itemtype = '\0';
+                    continue;
+                }
+
+                which_type = TYP_ARTIFACT;
+                array_size = maxartifact;
+                break;
+
+            case ESCAPE:
+                return;
+
+            default:
+                wstandout(hw);
+                mvwaddstr(hw, 10, 0, "We don't stock any of those.");
+                wstandend(hw);
+                itemtype = '\0';
+                continue;
+        }
+    }
+    while (array_size == 0);
+
+    which_one = array_size;
+
+    do
+    {
+        const struct magic_item   *m_item;
+
+        display_postinfo();
+
+        mpos = 0;
+        sprintf(buf, "Which kind of %s do you wish to have (* for list)? ",
+            things[which_type].mi_name);
+
+        mvwaddstr(hw, 9, 0, buf);
+        
+        touchwin(hw);
+        wrefresh(hw);
+        buf[0] = '\0';
+
+        switch (get_string(buf, hw))
+        {
+            case QUIT:
+            case ESCAPE:
+                itemtype = '\0';
+                goto buy_more;
+        }
+
+        if (buf[0] == '*')      /* print list */
+        {
+            add_line(" ID  BASECOST NAME");
+
+            switch (which_type)
+            {
+                case TYP_RING:
+                case TYP_POTION:
+                case TYP_STICK:
+                case TYP_SCROLL:
+                case TYP_FOOD:
+
+                    for(i=0,m_item=magic_array; i < array_size; i++, m_item++)
+                        if (!is_spell && m_item->mi_worth > 0)
+                        {
+                            sprintf(buf, "%3d) %8d %s", i, m_item->mi_worth,
+                                m_item->mi_name);
+                            add_line(buf);
+                        }
+                    break;
+
+                case TYP_ARMOR:
+                    for (i = 0; i < array_size; i++)
+                        if (!is_spell && armors[i].a_worth > 0)
+                        {
+                            sprintf(buf, "%3d) %8d %s", i, armors[i].a_worth,
+                                armors[i].a_name);
+
+                            add_line(buf);
+                        }
+                    break;
+
+                case TYP_WEAPON:
+                    for (i = 0; i < array_size; i++)
+                        if (!is_spell && weaps[i].w_worth > 0)
+                        {
+                            sprintf(buf, "%3d) %8d %s", i, weaps[i].w_worth,
+                                weaps[i].w_name);
+                            add_line(buf);
+                        }
+                    break;
+
+                case TYP_ARTIFACT:
+                    for (i = 0; i < array_size; i++)
+                    {
+                        sprintf(buf, "%3d) %8d %s", i, arts[i].ar_worth,
+                            arts[i].ar_name);
+                        add_line(buf);
+                    }
+                    break;
+
+                default:
+                    add_line("What a strange type.");
+            }
+
+            end_line();
+            touchwin(hw);
+            wrefresh(hw);
+            continue;
+        }
+
+        if (isdigit(buf[0]))
+            which_one = atoi(buf);
+        else
+            switch (which_type)
+            {
+                case TYP_RING:
+                case TYP_POTION:
+                case TYP_STICK:
+                case TYP_SCROLL:
+                case TYP_FOOD:
+                    for (i=0,m_item=magic_array; i < array_size; i++, m_item++)
+                        if (strcmp(buf, m_item->mi_name) == 0)
+                            which_one = i;
+                    break;
+
+                case TYP_ARMOR:
+                    for (i = 0; i < array_size; i++)
+                        if (strcmp(buf, armors[i].a_name) == 0)
+                            which_one = i;
+                    break;
+
+                case TYP_WEAPON:
+                    for (i = 0; i < array_size; i++)
+                        if (strcmp(buf, weaps[i].w_name) == 0)
+                            which_one = i;
+                    break;
+
+                case TYP_ARTIFACT:
+                    for (i = 0; i < array_size; i++)
+                        if (strcmp(buf, arts[i].ar_name) == 0)
+                            which_one = i;
+                    break;
+
+                default:
+                    msg("What a strange type.");
+            }
+
+        if (which_one < 0 || which_one >= array_size)
+        {
+            wstandout(hw);
+            mvwaddstr(hw, 10, 0, "Type the name or an ID number.");
+            wstandend(hw);
+        }
+    }
+    while (which_one < 0 || which_one >= array_size);
+
+    item = new_item(sizeof *obj);
+    obj = OBJPTR(item);
+
+    if (which_type == TYP_ARTIFACT)
+    {
+        new_artifact(which_one, obj);
+        add_pack(item, NOMESSAGE);
+        itemtype = '\0';
+        goto buy_more;
+    }
+
+    obj->o_type = itemtype;
+    obj->o_which = which_one;
+    obj->o_mark[0] = '\0';
+    obj->o_group = 0;
+    obj->o_count = 1;
+    obj->o_weight = 0;
+    obj->o_dplus = obj->o_hplus = 0;
+    obj->o_worth = 0;
+
+    if (!is_spell)
+    {
+        plus_or_minus = -100;
+
+        do
+        {
+            mvwaddstr(hw, 10, 0, "Do you want the cursed, blessed, or normal"
+                                 " version? (c, b, n) [n]");
+            touchwin(hw);
+            wrefresh(hw);
+
+	    blessed = cursed = FALSE;
+            switch (readcharw(hw))
+            {
+                case ESCAPE:
+                    discard(item);
+                    itemtype = '\0';
+                    goto buy_more;
+
+                case 'c':
+                    cursed = TRUE;
+                    plus_or_minus = 0;
+                    break;
+
+                case 'b':
+                    blessed = TRUE;
+                    plus_or_minus = 0;
+                    break;
+
+                case 'n':
+                case ' ':
+                    plus_or_minus = 0;
+                    break;
+
+                default:
+                    wstandout(hw);
+                    mvwaddstr(hw,11,0,"Type 'c' for cursed, 'b' for blessed, "
+                                      "or 'n' for normal");
+                    wstandend(hw);
+            }
+        }
+        while (plus_or_minus == -100);
+    }
+
+    /* else used blessed, cursed from flags parameter */
+
+    if (which_type == TYP_WEAPON)
+        init_weapon(obj, which_one);
+
+    obj->o_flags |= ISKNOW;
+
+    if (cursed)
+    {
+        plus_or_minus = -(rnd(2) + 1);
+        obj->o_flags |= ISCURSED;
+    }
+    else if (blessed)
+    {
+        plus_or_minus = (rnd(3) + 1);
+        obj->o_flags |= ISBLESSED;
+    }
+    else
+    {
+        plus_or_minus = 0;
+        obj->o_flags |= ISNORMAL;
+    }
+
+    switch (which_type)
+    {
+        case TYP_WEAPON:
+            obj->o_hplus += plus_or_minus;
+            obj->o_dplus += plus_or_minus;
+            break;
+
+        case TYP_ARMOR:
+            obj->o_weight = armors[which_one].a_wght;
+            obj->o_ac = armors[which_one].a_class - plus_or_minus;
+            break;
+
+        case TYP_STICK:
+            fix_stick(obj);
+            break;
+
+        case TYP_RING:
+            obj->o_ac = plus_or_minus;
+            break;
+
+        case TYP_SCROLL:
+        case TYP_POTION:
+            obj->o_weight = things[which_type].mi_wght;
+            break;
+
+        case TYP_FOOD:
+		    break;
+			
+        default:
+            msg("That's a strange thing to try to own.");
+			discard(item);
+            itemtype = '\0';
+            goto buy_more;
+    }
+
+    obj->o_worth = get_worth(obj) * (luck + level / 15 + 1);
+    describe_it(obj);
+
+    if (!wizard && obj->o_worth > EFFECTIVE_PURSE)
+    {
+        wstandout(hw);
+        mvwaddstr(hw, 12, 0, "Unfortunately, you can't afford it.");
+        wstandend(hw);
+        wclrtoeol(hw);
+        touchwin(hw);
+	wrefresh(hw);
+		wait_for(' ');
+		discard(item);
+        itemtype = '\0';
+        goto buy_more;
+    }
+
+    mvwaddstr(hw, 12, 0, "Do you want it? [y] ");
+    wclrtoeol(hw);
+    touchwin(hw);
+    wrefresh(hw);
+
+    switch (readcharw(hw))
+    {
+        case ESCAPE:
+        case 'n':
+            msg("");
+			discard(item);
+            itemtype = '\0';
+            goto buy_more;
+    }
+
+    /* The hero bought the item here */
+
+    mpos = 0;
+
+    if (add_pack(item, NOMESSAGE) && !is_spell)
+    {
+	    if (!wizard)
+		{
+		    purse -= obj->o_worth; /* take his money */
+            ++player.t_trans;
+		}
+		
+        trans_line();   /* show remaining deals */
+
+        switch(which_type)
+        {
+            case TYP_RING:
+            case TYP_STICK:
+            case TYP_SCROLL:
+            case TYP_POTION:
+                know_items[which_type][which_one] = TRUE;
+        }
+    }
+}
+
+/*
+    sell_it()
+        Sell an item to the trading post
+*/
+
+void
+sell_it(void)
+{
+    struct object *obj;
+    struct linked_list  *item;
+    char buf[2 * LINELEN];
+
+    wclear(cw);
+
+    if ((item = get_item("sell", 0)) == NULL)
+        return;
+
+    obj = OBJPTR(item);
+    msg("");
+    display_postinfo();
+    touchwin(hw);
+    wrefresh(hw);
+
+    if ((obj->o_type == ARTIFACT) || (obj->o_worth = get_worth(obj)) == 0)
+    {
+        mpos = 0;
+        msg("We don't buy those.");
+
+        if (is_wearing(R_ADORNMENT) && rnd(10) < 4)
+            msg("How about that %s ring instead?", r_stones[R_ADORNMENT]);
+
+        return;
+    }
+
+    describe_it(obj);
+    mvwaddstr(hw, 12, 0, "Do you want to sell it? [n] ");
+    touchwin(hw);
+    wrefresh(hw);
+
+    switch( readcharw(hw) )
+    {
+        case 'y':
+            break;
+        default:
+            msg("");
+            if (is_wearing(R_ADORNMENT))
+                msg("How about that %s ring instead?",
+                    r_stones[R_ADORNMENT]);
+            return;
+    }
+
+    rem_pack(obj);
+    purse += obj->o_worth; /* give him his money */
+    ++player.t_trans;
+
+    sprintf(buf, "Sold %s.  Hit space to continue.",
+        inv_name(obj, LOWERCASE));
+    discard(item);
+
+    mvwaddstr(hw, 13, 0, buf);
+    touchwin(hw);
+    wrefresh(hw);
+    wait_for(' ');
+}
+
+/*
+    describe_it()
+        Laud or condemn the object
+*/
+
+extern char *inv_name();
+
+void
+describe_it(struct object *obj)
+{
+    static char *cursed_d[] =
+    {
+        "worthless hunk of junk",
+        "shoddy piece of trash",
+        "piece of rusty garbage",
+        "example of terrible workmanship",
+        "cheap hack"
+    };
+
+    static char *normal_d[] =
+    {
+        "journeyman's piece",
+        "fine deal",
+        "great bargain",
+        "good find",
+        "real value",
+        "piece of honest workmanship",
+        "steal",
+        "purchase worth making",
+        "inexpensive product"
+    };
+
+    static char *blessed_d[] =
+    {
+        "magnificant masterpiece",
+        "quality product",
+        "exceptional find",
+        "unbeatable value",
+        "rare beauty",
+        "superior product",
+        "well-crafted item"
+    };
+
+    char    *charp;
+    char    buf[2 * LINELEN];
+
+    if (obj->o_flags & ISBLESSED)
+        charp = blessed_d[rnd(sizeof(blessed_d) / sizeof(char *))];
+    else if (obj->o_flags & ISCURSED)
+        charp = cursed_d[rnd(sizeof(cursed_d) / sizeof(char *))];
+    else
+        charp = normal_d[rnd(sizeof(normal_d) / sizeof(char *))];
+
+    sprintf(buf, "It's a%s %s worth %d pieces of gold.",
+        vowelstr(charp), charp, obj->o_worth);
+
+    mvwaddstr(hw, 10, 0, inv_name(obj, TRUE));
+    mvwaddstr(hw, 11, 0, buf);
+    wclrtoeol(hw);
+}
+
+/*
+    open_market()
+        Retruns TRUE when ok do to transacting
+*/
+
+int
+open_market(void)
+{
+    int maxtrans = is_wearing(R_ADORNMENT) ? MAXPURCH + 4 : MAXPURCH;
+
+    if (wizard || player.t_trans < maxtrans || (level == 0))
+        return(TRUE);
+    else
+    {
+        msg("The market is closed. The stairs are that-a-way.");
+        return(FALSE);
+    }
+}
+
+/*
+    get_worth()
+        Calculate an objects worth in gold
+*/
+
+int
+get_worth(struct object *obj)
+{
+    long    worth = 0;
+    int wh = obj->o_which;
+    int blessed = obj->o_flags & ISBLESSED;
+    int cursed = obj->o_flags & ISCURSED;
+
+    switch (obj->o_type)
+    {
+        case FOOD:
+            if (wh < maxfoods)
+            {
+                worth = obj->o_count * fd_data[wh].mi_worth;
+                if (blessed)
+                    worth *= 2;
+            }
+            break;
+
+        case WEAPON:
+            if (wh < maxweapons)
+            {
+                worth = weaps[wh].w_worth;
+                worth *= obj->o_count * (2 +
+                        (4 * obj->o_hplus +
+                        4 * obj->o_dplus));
+
+                if (obj->o_flags & ISSILVER)
+                    worth *= 2;
+
+                if (obj->o_flags & ISPOISON)
+                    worth *= 2;
+
+                if (obj->o_flags & ISZAPPED)
+                    worth += 20 * obj->o_charges;
+            }
+            break;
+
+        case ARMOR:
+            if (wh < maxarmors)
+            {
+                int plusses = armors[wh].a_class - obj->o_ac;
+
+                worth = armors[wh].a_worth;
+
+                if (plusses > 0)
+                    worth *= (1 + (10 *
+                        (armors[wh].a_class - obj->o_ac)));
+            }
+            break;
+
+        case SCROLL:
+            if (wh < maxscrolls)
+                worth = s_magic[wh].mi_worth;
+            break;
+
+        case POTION:
+            if (wh < maxpotions)
+                worth = p_magic[wh].mi_worth;
+            break;
+
+        case RING:
+            if (wh < maxrings)
+            {
+                worth = r_magic[wh].mi_worth;
+                worth += obj->o_ac * 40;
+            }
+            break;
+
+        case  STICK:
+            if (wh < maxsticks)
+            {
+                worth = ws_magic[wh].mi_worth;
+                worth += 20 * obj->o_charges;
+            }
+            break;
+
+        case ARTIFACT:
+            if (wh < maxartifact)
+                worth = arts[wh].ar_worth;
+            break;
+
+        default:
+            worth = 0;
+    }
+
+    if (obj->o_flags & ISPROT)  /* 300% more for protected */
+        worth *= 3;
+
+    if (blessed)        /* 250% more for blessed */
+        worth = 5 * worth / 2;
+    else if (cursed)    /* half for cursed */
+        worth /= 2;
+
+    if (obj->o_flags & (CANRETURN | ISOWNED))
+        worth *= 4;
+    else if (obj->o_flags & CANRETURN)
+        worth *= 2;
+    else if (obj->o_flags & ISLOST)
+        worth /= 3;
+
+    return(max(0, worth)); /* anything is worth at least one gold piece */
+}
+
+/*
+    trans_line()
+        Show how many transactions the hero has left
+*/
+
+void
+trans_line(void)
+{
+    char buf[2 * LINELEN];
+    int adorned = is_wearing(R_ADORNMENT);
+
+    if (level == 0 && purse > 0)
+        sprintf(buf, "You still have %d pieces of gold left.", purse);
+    else if (purse == 0)
+        sprintf(buf, "You have no money left.");
+    else if (!wizard)
+        sprintf(buf, "You have %d transactions and %d gold pieces remaining.",
+            max(0, (adorned ? MAXPURCH + 4 : MAXPURCH) - player.t_trans),
+            EFFECTIVE_PURSE);
+    else
+        sprintf(buf, "You have infinite transactions remaining.");
+
+    mvwaddstr(hw, LINES - 2, 0, buf);
+}