view arogue7/trader.c @ 305:3900f3cfe07d

Rogue V4: fix arithmetic operations on boolean variables. Monsters created by scrolls should now have their placement randomized correctly again.
author John "Elwin" Edwards
date Thu, 15 Apr 2021 20:55:34 -0400
parents f9ef86cf22b2
children ad2570b5b21f
line wrap: on
line source

/*
 * trader.c - Anything to do with trading posts
 *
 * Advanced Rogue
 * Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
 * 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.
 */

/*
 * Anything to do with trading posts
 */

#include <ctype.h>
#include <string.h>
#include "curses.h"
#include "rogue.h"

bool open_market(void);
void trans_line(void);
char *typ_name(struct object *obj);


/*
 * buy_it:
 *	Buy the item on which the hero stands
 */
void
buy_it(void)
{
	reg int wh;
	struct linked_list *item;

	if (purse <= 0) {
	    msg("You have no money.");
	    return;
	}
	if (curprice < 0) {		/* if not yet priced */
	    wh = price_it();
	    if (!wh)			/* nothing to price */
		return;
	    msg("Do you want to buy it? ");
	    do {
		wh = tolower(readchar());
		if (wh == ESCAPE || wh == 'n') {
		    msg("");
		    return;
		}
	    } until(wh == 'y');
	}
	mpos = 0;
	if (curprice > purse) {
	    msg("You can't afford to buy that %s !",curpurch);
	    return;
	}
	/*
	 * See if the hero has done all his transacting
	 */
	if (!open_market())
	    return;
	/*
	 * The hero bought the item here
	 */
	item = find_obj(hero.y, hero.x);
	mpos = 0;
	if (add_pack(NULL, TRUE, &item)) {	/* try to put it in his pack */
	    purse -= curprice;		/* take his money */
	    ++trader;			/* another transaction */
	    trans_line();		/* show remaining deals */
	    curprice = -1;		/* reset stuff */
	    curpurch[0] = 0;
	    whatis (item);		/* identify it after purchase */
	    (OBJPTR(item))->o_flags &= ~ISPOST; /* turn off ISPOST */
	    msg("%s", inv_name(OBJPTR(item), TRUE));
	}
}

/*
 * do_post:
 *	Put a trading post room and stuff on the screen
 * startup: True if equipping the player at the beginning of the game
 */
void
do_post(bool startup)
{
	coord tp;
	reg int i, j, k;
	reg struct room *rp;
	reg struct object *op;
	reg struct linked_list *ll;

	o_free_list(lvl_obj);		/* throw old items away */

	for (rp = rooms; rp < &rooms[MAXROOMS]; rp++)
	    rp->r_flags = ISGONE;		/* kill all rooms */

	rp = &rooms[0];				/* point to only room */
	rp->r_flags = 0;			/* this room NOT gone */
	rp->r_max.x = 40;
	rp->r_max.y = 10;			/* 10 * 40 room */
	rp->r_pos.x = (cols - rp->r_max.x) / 2;	/* center horizontal */
	rp->r_pos.y = 1;			/* 2nd line */
	draw_room(rp);				/* draw the only room */

	/* Are we equipping the player? */
	if (startup) {
	    int wpt;

	    /*
	     * Give the rogue some weaponry.  
	     */
	    for (wpt=0; wpt<MAXWEAPONS; wpt++) {
		ll = spec_item(WEAPON, wpt, rnd(2), rnd(2)+1);
		attach(lvl_obj, ll);
		op = OBJPTR(ll);
		op->o_flags |= (ISPOST | ISKNOW);
		do {
		    rnd_pos(rp,&tp);
		} until (mvinch(tp.y, tp.x) == FLOOR);
		op->o_pos = tp;
		mvaddch(tp.y,tp.x,op->o_type);
	    }

	    /*
	     * And his suit of armor.......
	     * Thieves can only wear leather armor,
	     * so make sure some is available for them.
	     */
	    for (i=0; i<MAXARMORS; i++) {
		ll = spec_item(ARMOR, i, 0, 0);
		attach(lvl_obj, ll);
		op = OBJPTR(ll);
		op->o_flags |= (ISPOST | ISKNOW);
		op->o_weight = armors[i].a_wght;
		do {
		    rnd_pos(rp,&tp);
		} until (mvinch(tp.y, tp.x) == FLOOR);
		op->o_pos = tp;
		mvaddch(tp.y,tp.x,op->o_type);
	    }

	    /* Now create some wands */
	    for (i=rnd(4)+2; i>0; i--) {
		switch (rnd(8)) {
		    case 0: j = WS_SLOW_M;
		    when 1: j = WS_TELMON;
		    when 2: j = WS_CONFMON;
		    when 3: j = WS_PARALYZE;
		    when 4: j = WS_MDEG;
		    when 5: j = WS_WONDER;
		    when 6: j = WS_FEAR;
		    when 7: j = WS_LIGHT;
		}
		ll = spec_item(STICK, j, 0, 0);
		attach(lvl_obj, ll);
		op = OBJPTR(ll);

		/* Let clerics and MU'S know what kind they are */
		switch (player.t_ctype) {
		    case C_MAGICIAN:
		    case C_CLERIC:
		    case C_DRUID:
			op->o_flags |= (ISPOST | ISKNOW);
		    otherwise:
			op->o_flags |= ISPOST;
		}
		fix_stick(op);
		do {
		    rnd_pos(rp,&tp);
		} until (mvinch(tp.y, tp.x) == FLOOR);
		op->o_pos = tp;
		mvaddch(tp.y,tp.x,op->o_type);
	    }

	    /* Now let's make some rings */
	    for (i=rnd(4)+3; i>0; i--) {
		k = 0;
		switch (rnd(15)) {
		case 0: j = R_PROTECT;	k = roll(1,2);
		when 1: j = R_ADDSTR;	k = roll(1,3);
		when 2: j = R_ADDHIT;	k = roll(1,3);
		when 3: j = R_ADDDAM;	k = roll(1,3);
		when 4: j = R_DIGEST;	k = 1;
		when 5: j = R_ADDINTEL;	k = roll(1,3);
		when 6: j = R_ADDWISDOM;k = roll(1,3);
		when 7: j = R_SUSABILITY;
		when 8: j = R_SEEINVIS;
		when 9: j = R_ALERT;
		when 10:j = R_HEALTH;
		when 11:j = R_HEROISM;
		when 12:j = R_FIRE;
		when 13:j = R_WARMTH;
		when 14:j = R_FREEDOM;
		}
		ll = spec_item(RING, j, k, 0);
		attach(lvl_obj, ll);
		op = OBJPTR(ll);

		/*
		 * Let fighters, assassins, monks, and thieves know what kind
		 * of rings these are.
		 */
		switch (player.t_ctype) {
		    case C_FIGHTER:
		    case C_THIEF:
		    case C_ASSASIN:
		    case C_MONK:
			op->o_flags |= (ISPOST | ISKNOW);
		    otherwise:
			op->o_flags |= ISPOST;
		}
		do {
		    rnd_pos(rp,&tp);
		} until (mvinch(tp.y, tp.x) == FLOOR);
		op->o_pos = tp;
		mvaddch(tp.y,tp.x,op->o_type);
	    }

	    /* Let's offer some potions */
	    for (i=rnd(3)+1; i>0; i--) {
		/* Choose the type of potion */
		if (i == 1 && player.t_ctype == C_ASSASIN) j = P_POISON;
		else switch (rnd(8)) {
		    case 0:	j = P_CLEAR;
		    when 1:	j = P_HEALING;
		    when 2:	j = P_MFIND;
		    when 3:	j = P_TFIND;
		    when 4:	j = P_HASTE;
		    when 5:	j = P_RESTORE;
		    when 6:	j = P_FLY;
		    when 7:	j = P_FFIND;
		}

		/* Make the potion */
		ll = spec_item(POTION, j, 0, 0);
		attach(lvl_obj, ll);
		op = OBJPTR(ll);
		op->o_flags |= ISPOST;

		/* Place the potion */
		do {
		    rnd_pos(rp,&tp);
		} until (mvinch(tp.y, tp.x) == FLOOR);
		op->o_pos = tp;
		mvaddch(tp.y,tp.x,op->o_type);
	    }

	    /* Let's offer some scrolls */
	    for (i=rnd(3)+1; i>0; i--) {
		/* Choose the type of scrolls */
		switch (rnd(8)) {
		    case 0:	j = S_CONFUSE;
		    when 1:	j = S_MAP;
		    when 2:	j = S_LIGHT;
		    when 3:	j = S_SLEEP;
		    when 4:	j = S_IDENT;
		    when 5:	j = S_GFIND;
		    when 6:	j = S_REMOVE;
		    when 7:	j = S_CURING;
		}

		/* Make the scroll */
		ll = spec_item(SCROLL, j, 0, 0);
		attach(lvl_obj, ll);
		op = OBJPTR(ll);
		op->o_flags |= ISPOST;

		/* Place the scroll */
		do {
		    rnd_pos(rp,&tp);
		} until (mvinch(tp.y, tp.x) == FLOOR);
		op->o_pos = tp;
		mvaddch(tp.y,tp.x,op->o_type);
	    }

	    /* And finally, let's get some food */
	    for (i=rnd(3)+1; i>0; i--) {
		ll = spec_item(FOOD, 0, 0, 0);
		attach(lvl_obj, ll);
		op = OBJPTR(ll);
		op->o_weight = things[TYP_FOOD].mi_wght;
		op->o_flags |= ISPOST;
		do {
		    rnd_pos(rp,&tp);
		} until (mvinch(tp.y, tp.x) == FLOOR);
		op->o_pos = tp;
		mvaddch(tp.y,tp.x,op->o_type);
	    }
	}
	else {
	    i = roll(10, 4);			/* 10 to 40 items */
	    for (; i > 0 ; i--) {		/* place all the items */
		ll = new_thing(ALL, TRUE);		/* get something */
		attach(lvl_obj, ll);
		op = OBJPTR(ll);
		op->o_flags |= ISPOST;		/* object in trading post */
		do {
		    rnd_pos(rp,&tp);
		} until (mvinch(tp.y, tp.x) == FLOOR);
		op->o_pos = tp;
		mvaddch(tp.y,tp.x,op->o_type);
	    }
	}
	wmove(cw,12,0);
	trader = 0;
	if (startup) {
	    waddstr(cw,"Welcome to Friendly Fiend's Equipage\n\r");
	    waddstr(cw,"====================================\n\r");
	}
	else {
	    waddstr(cw,"Welcome to Friendly Fiend's Flea Market\n\r");
	    waddstr(cw,"=======================================\n\r");
	}
	waddstr(cw,"$: Prices object that you stand upon.\n\r");
	waddstr(cw,"#: Buys the object that you stand upon.\n\r");
	waddstr(cw,"%: Trades in something in your pack for gold.\n\r");
	trans_line();
}


/*
 * get_worth:
 *	Calculate an objects worth in gold
 */
int
get_worth(struct object *obj)
{
	reg int worth, wh;

	worth = 0;
	wh = obj->o_which;
	switch (obj->o_type) {
	    case FOOD:
		worth = 2;
	    when WEAPON:
		if (wh < MAXWEAPONS) {
		    worth = weaps[wh].w_worth;
		    worth += s_magic[S_ALLENCH].mi_worth * 
		   		 (obj->o_hplus + obj->o_dplus);
		}
	    when ARMOR:
		if (wh < MAXARMORS) {
		    worth = armors[wh].a_worth;
		    worth += s_magic[S_ALLENCH].mi_worth * 
				(armors[wh].a_class - obj->o_ac);
		}
	    when SCROLL:
		if (wh < MAXSCROLLS)
		    worth = s_magic[wh].mi_worth;
	    when POTION:
		if (wh < MAXPOTIONS)
		    worth = p_magic[wh].mi_worth;
	    when RING:
		if (wh < MAXRINGS) {
		    worth = r_magic[wh].mi_worth;
		    worth += obj->o_ac * 40;
		}
	    when STICK:
		if (wh < MAXSTICKS) {
		    worth = ws_magic[wh].mi_worth;
		    worth += 20 * obj->o_charges;
		}
	    when MM:
		if (wh < MAXMM) {
		    worth = m_magic[wh].mi_worth;
		    switch (wh) {
			case MM_BRACERS:	worth += 40  * obj->o_ac;
			when MM_PROTECT:	worth += 60  * obj->o_ac;
			when MM_DISP:		/* ac already figured in price*/
			otherwise:		worth += 20  * obj->o_ac;
		    }
		}
	    when RELIC:
		if (wh < MAXRELIC) {
		    worth = rel_magic[wh].mi_worth;
		    if (wh == quest_item) worth *= 10;
		}
	    otherwise:
		worth = 0;
	}
	if (obj->o_flags & ISPROT)	/* 300% more for protected */
	    worth *= 3;
	if (obj->o_flags &  ISBLESSED)	/* 50% more for blessed */
	    worth = worth * 3 / 2;
	if (obj->o_flags & ISCURSED)	/* half for cursed */
	    worth /= 2;
	if (worth < 0)
	    worth = 0;
	return worth;
}

/*
 * open_market:
 *	Retruns TRUE when ok do to transacting
 */
bool
open_market(void)
{
	if (trader >= MAXPURCH && !wizard && level != 0) {
	    msg("The market is closed. The stairs are that-a-way.");
	    return FALSE;
	}
	else {
	    return TRUE;
	}
}

/*
 * price_it:
 *	Price the object that the hero stands on
 */
bool
price_it(void)
{
	reg struct linked_list *item;
	reg struct object *obj;
	reg int worth;
	reg char *str;

	if (!open_market())		/* after buying hours */
	    return FALSE;
	if ((item = find_obj(hero.y,hero.x)) == NULL) {
	    debug("Can't find the item");
	    return FALSE;
	}
	obj = OBJPTR(item);
	worth = get_worth(obj);
	if (worth < 0) {
	    msg("That's not for sale.");
	    return FALSE;
	}
	if (worth < 25)
	    worth = 25;

	/* Our shopkeeper is affected by the person's charisma */
	worth = (int) ((float) worth * (17. / (float)pstats.s_charisma));
	str = inv_name(obj, TRUE);
	msg("%s for only %d pieces of gold", str, worth);
	curprice = worth;		/* save price */
	strcpy(curpurch,str);		/* save item */
	return TRUE;
}



/*
 * sell_it:
 *	Sell an item to the trading post
 */
void
sell_it(void)
{
	reg struct linked_list *item;
	reg struct object *obj;
	reg int wo, ch;

	if (!open_market())		/* after selling hours */
	    return;

	if ((item = get_item(pack, "sell", ALL, FALSE, FALSE)) == NULL)
	    return;
	obj = OBJPTR(item);
	wo = get_worth(obj);
	if (wo <= 0) {
	    mpos = 0;
	    msg("We don't buy those.");
	    return;
	}
	if (wo < 25)
	    wo = 25;
	msg("Your %s is worth %d pieces of gold.",typ_name(obj),wo);
	msg("Do you want to sell it? ");
	do {
	    ch = tolower(readchar());
	    if (ch == ESCAPE || ch == 'n') {
		msg("");
		return;
	    }
	} until (ch == 'y');
	mpos = 0;
	if (drop(item) == TRUE) {		/* drop this item */	
	    purse += wo;			/* give him his money */
	    ++trader;				/* another transaction */
	    wo = obj->o_count;
	    if (obj->o_group == 0) 		/* dropped one at a time */
		obj->o_count = 1;
	    msg("Sold %s",inv_name(obj,TRUE));
	    obj->o_count = wo;
	    trans_line();			/* show remaining deals */
	}
}

/*
 * trans_line:
 *	Show how many transactions the hero has left
 */
void
trans_line(void)
{
	if (level == 0)
	    sprintf(prbuf, "You are welcome to spend whatever you have.");
	else if (!wizard)
	    sprintf(prbuf,"You have %d transactions remaining.",
		    MAXPURCH - trader);
	else
	    sprintf(prbuf,
		"You have infinite transactions remaining oh great wizard.");
	mvwaddstr(cw,lines - 3,0,prbuf);
}



/*
 * typ_name:
 * 	Return the name for this type of object
 */
char *
typ_name(struct object *obj)
{
	static char buff[20];
	reg int wh;

	switch (obj->o_type) {
		case POTION:  wh = TYP_POTION;
		when SCROLL:  wh = TYP_SCROLL;
		when STICK:   wh = TYP_STICK;
		when RING:    wh = TYP_RING;
		when ARMOR:   wh = TYP_ARMOR;
		when WEAPON:  wh = TYP_WEAPON;
		when MM:      wh = TYP_MM;
		when FOOD:    wh = TYP_FOOD;
		when RELIC:   wh = TYP_RELIC;
		otherwise:    wh = -1;
	}
	if (wh < 0)
		strcpy(buff,"unknown");
	else
		strcpy(buff,things[wh].mi_name);
	return (buff);
}