/* ************************************************************************
* File: shop.c Part of CircleMUD *
* Usage: shopkeepers: loading config files, spec procs. *
* *
* All rights reserved. See license.doc for complete information. *
* *
* Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University *
* CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991. *
************************************************************************ */
/***
* The entire shop rewrite for Circle 3.0 was done by Jeff Fink. Thanks Jeff!
***/
/*
* This file contains the functions to load the world files into memory
* into the stock CircleMUD arrays.
*
* You should update this code to match the code in your MUD if it's been
* changed from stock in any way.
*/
#ifndef __SHOP_C__
#define __SHOP_C__
#include "sysdep.h"
#include "structs.h"
#include "db.h"
#include "main.h"
#include "utils.h"
#include "zone.h"
#include "dao.h"
#include "shop.h"
/* define */
#define strn_cmp strncmp
/* extern functions */
obj_rnum real_object(obj_vnum vnum);
mob_rnum real_mobile(mob_vnum vnum);
char *fread_string(FILE *fl, const char *error);
int zoneNum_forVnum(int vnum);
/* extern vars */
extern const char *item_types[];
/* internal vars */
struct shop_data *shop_index;
int top_shop = -1;
int cmd_say, cmd_tell, cmd_emote, cmd_slap, cmd_puke;
/* internal funcs */
int read_type_list(FILE *shop_f, struct shop_buy_data *list, int new_format, int max);
int read_list(FILE *shop_f, struct shop_buy_data *list, int new_format, int max, int type);
/* val == obj_vnum and obj_rnum (?) */
int add_to_list(struct shop_buy_data *list, int type, int *len, int *val)
{
if (*val != NOTHING) {
if (*len < MAX_SHOP_OBJ) {
if (type == LIST_PRODUCE)
*val = real_object(*val);
if (*val != NOTHING) {
BUY_TYPE(list[*len]) = *val;
BUY_WORD(list[(*len)++]) = NULL;
} else
*val = NOTHING;
return (FALSE);
} else
return (TRUE);
}
return (FALSE);
}
int end_read_list(struct shop_buy_data *list, int len, int error)
{
if (error)
log("SYSERR: Raise MAX_SHOP_OBJ constant in shop.h to %d", len + error);
BUY_WORD(list[len]) = NULL;
BUY_TYPE(list[len++]) = NOTHING;
return (len);
}
void read_line(FILE *shop_f, const char *string, void *data)
{
char buf[READ_SIZE];
if (!get_line(shop_f, buf) || !sscanf(buf, string, data)) {
log("SYSERR: Error in shop #%d, near '%s' with '%s'", SHOP_NUM(top_shop), buf, string);
exit(1);
}
}
int read_list(FILE *shop_f, struct shop_buy_data *list, int new_format,
int max, int type)
{
int count, temp, len = 0, error = 0;
if (new_format) {
for (;;) {
read_line(shop_f, "%d", &temp);
if (temp < 0) /* Always "-1" the string. */
break;
error += add_to_list(list, type, &len, &temp);
}
} else
for (count = 0; count < max; count++) {
read_line(shop_f, "%d", &temp);
error += add_to_list(list, type, &len, &temp);
}
return (end_read_list(list, len, error));
}
/* END_OF inefficient. */
int read_type_list(FILE *shop_f, struct shop_buy_data *list,
int new_format, int max)
{
int tindex, num, len = 0, error = 0;
char *ptr;
char buf[MAX_STRING_LENGTH];
if (!new_format)
return (read_list(shop_f, list, 0, max, LIST_TRADE));
do {
fgets(buf, sizeof(buf), shop_f);
if ((ptr = strchr(buf, ';')) != NULL)
*ptr = '\0';
else
*(END_OF(buf) - 1) = '\0';
num = NOTHING;
if (strncmp(buf, "-1", 4) != 0)
for (tindex = 0; *item_types[tindex] != '\n'; tindex++)
if (!strncasecmp(item_types[tindex], buf, strlen(item_types[tindex]))) {
num = tindex;
strcpy(buf, buf + strlen(item_types[tindex])); /* strcpy: OK (always smaller) */
break;
}
ptr = buf;
if (num == NOTHING) {
sscanf(buf, "%d", &num);
while (!isdigit(*ptr))
ptr++;
while (isdigit(*ptr))
ptr++;
}
while (isspace(*ptr))
ptr++;
while (isspace(*(END_OF(ptr) - 1)))
*(END_OF(ptr) - 1) = '\0';
error += add_to_list(list, LIST_TRADE, &len, &num);
if (*ptr)
BUY_WORD(list[len - 1]) = strdup(ptr);
} while (num >= 0);
return (end_read_list(list, len, error));
}
char *read_shop_message(int mnum, room_vnum shr, FILE *shop_f, const char *why)
{
int cht, ss = 0, ds = 0, err = 0;
char *tbuf;
if (!(tbuf = fread_string(shop_f, why)))
return (NULL);
for (cht = 0; tbuf[cht]; cht++) {
if (tbuf[cht] != '%')
continue;
if (tbuf[cht + 1] == 's')
ss++;
else if (tbuf[cht + 1] == 'd' && (mnum == 5 || mnum == 6)) {
if (ss == 0) {
log("SYSERR: Shop #%d has %%d before %%s, message #%d.", shr, mnum);
err++;
}
ds++;
} else if (tbuf[cht + 1] != '%') {
log("SYSERR: Shop #%d has invalid format '%%%c' in message #%d.", shr, tbuf[cht + 1], mnum);
err++;
}
}
if (ss > 1 || ds > 1) {
log("SYSERR: Shop #%d has too many specifiers for message #%d. %%s=%d %%d=%d", shr, mnum, ss, ds);
err++;
}
if (err) {
free(tbuf);
return (NULL);
}
return (tbuf);
}
void boot_the_shops(FILE *shop_f, char *filename, int rec_count)
{
char *buf, buf2[256];
int temp, count, new_format = FALSE;
struct shop_buy_data list[MAX_SHOP_OBJ + 1];
int done = FALSE;
snprintf(buf2, sizeof(buf2), "beginning of shop file %s", filename);
while (!done) {
buf = fread_string(shop_f, buf2);
if (*buf == '#') { /* New shop */
sscanf(buf, "#%d\n", &temp);
snprintf(buf2, sizeof(buf2), "shop #%d in shop file %s", temp, filename);
free(buf); /* Plug memory leak! */
top_shop++;
if (!top_shop)
CREATE(shop_index, struct shop_data, rec_count);
SHOP_NUM(top_shop) = temp;
temp = read_list(shop_f, list, new_format, MAX_PROD, LIST_PRODUCE);
CREATE(shop_index[top_shop].producing, obj_vnum, temp);
for (count = 0; count < temp; count++)
SHOP_PRODUCT(top_shop, count) = BUY_TYPE(list[count]);
read_line(shop_f, "%f", &SHOP_BUYPROFIT(top_shop));
read_line(shop_f, "%f", &SHOP_SELLPROFIT(top_shop));
temp = read_type_list(shop_f, list, new_format, MAX_TRADE);
CREATE(shop_index[top_shop].type, struct shop_buy_data, temp);
for (count = 0; count < temp; count++) {
SHOP_BUYTYPE(top_shop, count) = BUY_TYPE(list[count]);
SHOP_BUYWORD(top_shop, count) = BUY_WORD(list[count]);
}
shop_index[top_shop].no_such_item1 = read_shop_message(0, SHOP_NUM(top_shop), shop_f, buf2);
shop_index[top_shop].no_such_item2 = read_shop_message(1, SHOP_NUM(top_shop), shop_f, buf2);
shop_index[top_shop].do_not_buy = read_shop_message(2, SHOP_NUM(top_shop), shop_f, buf2);
shop_index[top_shop].missing_cash1 = read_shop_message(3, SHOP_NUM(top_shop), shop_f, buf2);
shop_index[top_shop].missing_cash2 = read_shop_message(4, SHOP_NUM(top_shop), shop_f, buf2);
shop_index[top_shop].message_buy = read_shop_message(5, SHOP_NUM(top_shop), shop_f, buf2);
shop_index[top_shop].message_sell = read_shop_message(6, SHOP_NUM(top_shop), shop_f, buf2);
read_line(shop_f, "%d", &SHOP_BROKE_TEMPER(top_shop));
read_line(shop_f, "%d", &SHOP_BITVECTOR(top_shop));
read_line(shop_f, "%hd", &SHOP_KEEPER(top_shop));
SHOP_KEEPER(top_shop) = real_mobile(SHOP_KEEPER(top_shop));
read_line(shop_f, "%d", &SHOP_TRADE_WITH(top_shop));
temp = read_list(shop_f, list, new_format, 1, LIST_ROOM);
CREATE(shop_index[top_shop].in_room, room_vnum, temp);
for (count = 0; count < temp; count++)
SHOP_ROOM(top_shop, count) = BUY_TYPE(list[count]);
read_line(shop_f, "%d", &SHOP_OPEN1(top_shop));
read_line(shop_f, "%d", &SHOP_CLOSE1(top_shop));
read_line(shop_f, "%d", &SHOP_OPEN2(top_shop));
read_line(shop_f, "%d", &SHOP_CLOSE2(top_shop));
SHOP_BANK(top_shop) = 0;
SHOP_SORT(top_shop) = 0;
SHOP_FUNC(top_shop) = NULL;
} else {
if (*buf == '$') /* EOF */
done = TRUE;
else if (strstr(buf, VERSION3_TAG)) /* New format marker */
new_format = TRUE;
free(buf); /* Plug memory leak! */
}
}
}
/*
* NEW CODE FOLLOWS!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
* NEW CODE FOLLOWS!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
* NEW CODE FOLLOWS!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
* NEW CODE FOLLOWS!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
* NEW CODE FOLLOWS!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*
* Did that get your attention?
*/
void shopMain_toDao(daoData_t *dao, struct shop_data *shop) {
dao_newScalar(dao, "keeper", "%s:%d",
zone_table[zoneNum_forVnum(mob_index[shop->keeper].vnum)].keyword,
mob_index[shop->keeper].vnum);
dao_newScalar(dao, "buyProfit", "%f", shop->profit_buy);
dao_newScalar(dao, "sellProfit", "%f", shop->profit_sell);
dao_newScalar(dao, "hourOpen1", "%d", shop->open1);
dao_newScalar(dao, "hourClose1", "%d", shop->close1);
dao_newScalar(dao, "hourOpen2", "%d", shop->open2);
dao_newScalar(dao, "hourClose2", "%d", shop->close2);
}
void shopMessages_toDao(daoData_t *parentDao, struct shop_data *shop) {
daoData_t *subDao = NULL;
subDao = dao_newChild(parentDao, "messages");
if (subDao == NULL) {
log("shopMessages_toDao(): dao_newChild() failed. Aborting.");
return;
}
dao_newScalar(subDao, "shopMissingItem", "%s", shop->no_such_item1);
dao_newScalar(subDao, "buyerMissingItem", "%s", shop->no_such_item2);
dao_newScalar(subDao, "noBuy", "%s", shop->do_not_buy);
dao_newScalar(subDao, "shopCantAfford", "%s", shop->missing_cash1);
dao_newScalar(subDao, "playerCantAfford", "%s", shop->missing_cash2);
dao_newScalar(subDao, "itemSold", "%s", shop->message_buy);
dao_newScalar(subDao, "itemBought", "%s", shop->message_sell);
}
void shopItems_toDao(daoData_t *parentDao, struct shop_data *shop) {
daoData_t *subDao = NULL;
int i = 0;
if (shop->producing) {
for (i = 0; shop->producing[i] && shop->producing[i] != NOTHING; i++) {
if (subDao == NULL) {
subDao = dao_newChild(parentDao, "items");
if (subDao == NULL) {
log("shopItems_toDao(): dao_newChild() failed. Aborting.");
return;
}
}
char buf[MAX_STRING_LENGTH] = { "\0" };
snprintf(buf, sizeof(buf), "%d", i + 1);
dao_newScalar(subDao, buf, "%s:%d",
zone_table[zoneNum_forVnum(obj_index[(shop->producing[i])].vnum)].keyword,
obj_index[(shop->producing[i])].vnum );
}
}
}
void shopTypes_toDao(daoData_t *parentDao, struct shop_data *shop) {
daoData_t *subDao = NULL;
int i = 0;
if (shop->type && shop->type[0].type != NOTHING) {
subDao = dao_newChild(parentDao, "types");
if (subDao == NULL) {
log("shopTypes_toDao(): dao_newChild() failed. Aborting.");
return;
}
for (i = 0; shop->type[i].type != NOTHING; i++) {
char buf[MAX_STRING_LENGTH] = { "\0" };
snprintf(buf, sizeof(buf), "%d", i + 1);
dao_newScalar(subDao, buf, "%s", item_types[(shop->type[i].type)]);
}
}
}
void shopRooms_toDao(daoData_t *parentDao, struct shop_data *shop) {
daoData_t *subDao = NULL;
int i = 0;
if (shop->in_room && shop->in_room[0] != NOWHERE) {
subDao = dao_newChild(parentDao, "rooms");
if (subDao == NULL) {
log("shopRooms_toDao(): dao_newChild() failed. Aborting.");
return;
}
for (i = 0; shop->in_room[i] != -1; i++) {
char buf[MAX_STRING_LENGTH] = { "\0" };
snprintf(buf, sizeof(buf), "%d", i + 1);
dao_newScalar(subDao, buf, "%s:%d",
zone_table[zoneNum_forVnum(shop->in_room[i])].keyword,
shop->in_room[i]);
}
}
}
void shopTrades_toDao(daoData_t *parentDao, struct shop_data *shop) {
daoData_t *subDao = NULL;
if (shop->with_who != 0) {
subDao = dao_newChild(parentDao, "flags");
dao_newScalar(subDao, "NOGOOD", "%s", YESNO(IS_SET(shop->with_who, TRADE_NOGOOD)));
dao_newScalar(subDao, "NOEVIL", "%s", YESNO(IS_SET(shop->with_who, TRADE_NOEVIL)));
dao_newScalar(subDao, "NONEUTRAL", "%s", YESNO(IS_SET(shop->with_who, TRADE_NONEUTRAL)));
dao_newScalar(subDao, "NOMAGIC_USER", "%s", YESNO(IS_SET(shop->with_who, TRADE_NOMAGIC_USER)));
dao_newScalar(subDao, "NOCLERIC", "%s", YESNO(IS_SET(shop->with_who, TRADE_NOCLERIC)));
dao_newScalar(subDao, "NOTHIEF", "%s", YESNO(IS_SET(shop->with_who, TRADE_NOTHIEF)));
dao_newScalar(subDao, "NOWARRIOR", "%s", YESNO(IS_SET(shop->with_who, TRADE_NOWARRIOR)));
}
}
/*
* And save the shop to DAO
*
* This is broken out into sub functions for readability's sake.
*/
void shopData_toDao(daoData_t *parentDao, struct shop_data *shop) {
if (shop == NULL) {
log("shopData_toDao(): invalid 'shop' struct shop_data.");
} else if (parentDao == NULL) {
log("shopData_toDao(): invalid 'parentDao' daoData_t.");
} else {
/* Declare some dao pointers */
daoData_t *shopDao = NULL;
/* Create DAO for the shop */
shopDao = dao_newChild(parentDao, "%d", shop->vnum);
if (shopDao == NULL) {
log("shopData_toDao(): dao_newChild() failed. Aborting.");
return;
}
/* Main shop data */
shopMain_toDao(shopDao, shop);
/* Messages */
shopMessages_toDao(shopDao, shop);
/* Shop Producing Items */
shopItems_toDao(shopDao, shop);
/* Item Types the shop trades in */
shopTypes_toDao(shopDao, shop);
/* Shop rooms */
shopRooms_toDao(shopDao, shop);
/* Trades */
shopTrades_toDao(shopDao, shop);
}
}
#endif /* __SHOP_C__ */