/******************************************************
Desolation of the Dragon MUD II
(C) 1997-2002 Jesse DeFer
http://www.dotd.com dotd@dotd.com
******************************************************/
/*static char rcsid[] = "$Id: currency.c,v 1.18 2002/10/12 20:06:09 dotd Exp $";*/
#include <sys/types.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "h/mud.h"
#include "h/currency.h"
#include "h/files.h"
#include "h/shops.h"
#include "h/key.h"
#define CURRENCY_FILE SYSTEM_DIR "currency.dat"
const char *const curr_types[] = {
"none", "gold", "silver", "bronze", "copper"
};
const char *const cap_curr_types[] = {
"None", "Gold", "Silver", "Bronze", "Copper"
};
CURR_INDEX_DATA *first_curr_index;
CURR_INDEX_DATA *last_curr_index;
CURR_INDEX_DATA *mud_curr_index;
int get_currency_type(char *type)
{
int x;
if(!str_cmp(type, "coin") || !str_cmp(type, "coins"))
return DEFAULT_CURR;
for(x = 0; x < MAX_CURR_TYPE; x++)
if(!str_cmp(type, curr_types[x]))
return x;
return CURR_NONE;
}
float get_worth(CURRENCY_DATA * c1, CURRENCY_DATA * c2)
{
if(!c1 || !c2)
return 0.0;
return ((float)c1->tsiints / (float)c2->tsiints);
}
short get_primary_curr(ROOM_INDEX_DATA *room)
{
if(!room)
return DEFAULT_CURR;
if(room->currindex)
return room->currindex->primary;
if(room->area->currindex)
return room->area->currindex->primary;
return mud_curr_index->primary;
}
char *get_primary_curr_str(ROOM_INDEX_DATA *room)
{
return (char *)cap_curr_types[get_primary_curr(room)];
}
void free_currency(CURR_INDEX_DATA * currindex, CURRENCY_DATA * curr)
{
UNLINK(curr, currindex->first_currency, currindex->last_currency, next_currency, prev_currency);
DISPOSE(curr);
}
void free_currindex(CURR_INDEX_DATA * currindex)
{
CURRENCY_DATA *curr;
if(!currindex)
return;
UNLINK(currindex, first_curr_index, last_curr_index, next_currindex, prev_currindex);
while((curr = currindex->first_currency))
free_currency(currindex, curr);
if(currindex->name)
STRFREE(currindex->name);
DISPOSE(currindex);
}
void free_currencies(void)
{
while(first_curr_index)
free_currindex(first_curr_index);
}
CURR_INDEX_DATA *make_currindex(void)
{
CURR_INDEX_DATA *currindex;
CREATE(currindex, CURR_INDEX_DATA, 1);
currindex->vnum = 0;
currindex->primary = CURR_NONE;
currindex->name = STRALLOC("Unnamed");
currindex->first_currency = NULL;
currindex->last_currency = NULL;
LINK(currindex, first_curr_index, last_curr_index, next_currindex, prev_currindex);
return currindex;
}
CURRENCY_DATA *make_currency(CURR_INDEX_DATA * currindex)
{
CURRENCY_DATA *curr;
CREATE(curr, CURRENCY_DATA, 1);
curr->type = CURR_NONE;
curr->tsiints = 0;
LINK(curr, currindex->first_currency, currindex->last_currency, next_currency, prev_currency);
return curr;
}
CURR_INDEX_DATA *find_currindex_vnum(int vnum)
{
CURR_INDEX_DATA *currindex;
if(!first_curr_index)
return NULL;
for(currindex = first_curr_index; currindex; currindex = currindex->next_currindex)
if(currindex->vnum == vnum)
return currindex;
return NULL;
}
CURRENCY_DATA *find_currency(CURR_INDEX_DATA * currindex, int type)
{
CURRENCY_DATA *curr;
if(!currindex || !currindex->first_currency)
return NULL;
for(curr = currindex->first_currency; curr; curr = curr->next_currency)
if(curr->type == type)
return curr;
return NULL;
}
void init_mud_curr_index(void)
{
CURRENCY_DATA *c;
int x;
mud_curr_index = make_currindex();
mud_curr_index->primary = DEFAULT_CURR;
STRFREE(mud_curr_index->name);
mud_curr_index->name = STRALLOC("MUD-Wide Currency");
for(x = 0; x < MAX_CURR_TYPE; x++)
{
c = make_currency(mud_curr_index);
c->type = x;
switch (x)
{
case CURR_GOLD:
c->tsiints = 500;
break;
case CURR_SILVER:
c->tsiints = 200;
break;
case CURR_BRONZE:
c->tsiints = 100;
break;
case CURR_COPPER:
c->tsiints = 10000;
break;
default:
c->tsiints = 150;
break;
}
}
}
int convert_curr(ROOM_INDEX_DATA *room, int amount, int fromtype, int totype)
{
CURR_INDEX_DATA *rc, *ac;
CURRENCY_DATA *from, *to;
if(!room)
{
bug("Non existant room passed to convert_curr.");
return -1;
}
rc = room->currindex;
ac = room->area->currindex;
if(!(from = find_currency(rc, fromtype)))
if(!(from = find_currency(ac, fromtype)))
from = find_currency(mud_curr_index, fromtype);
if(!(to = find_currency(rc, totype)))
if(!(to = find_currency(ac, totype)))
to = find_currency(mud_curr_index, totype);
if(!from || !to)
{
bug("Currency conversion returns -1 (%d to %d) for room %d.", fromtype, totype, room->vnum);
return -1;
}
if(from == to)
return amount;
return (int)((float)amount * get_worth(from, to));
}
int obj_primary_curr_value(ROOM_INDEX_DATA *room, OBJ_DATA *obj)
{
if(!obj)
{
bug("No obj given to obj_primary_curr_value.");
return -1;
}
return convert_curr(room, obj->cost, obj->currtype, get_primary_curr(room));
}
void assign_currindex(ROOM_INDEX_DATA *room)
{
if(!room)
{
bug("CURRENCY: No room.");
return;
}
if(room->currvnum)
{
room->currindex = find_currindex_vnum(room->currvnum);
return;
}
if(room->area->currvnum)
{
room->currindex = find_currindex_vnum(room->area->currvnum);
return;
}
room->currindex = mud_curr_index;
}
static void save_currency(void)
{
CURR_INDEX_DATA *currindex;
CURRENCY_DATA *curr;
FILE *fp;
if((fp = FileOpen(CURRENCY_FILE, "w")) == NULL)
{
bug("Unable to write currency file: %s", CURRENCY_FILE);
return;
}
for(currindex = first_curr_index; currindex; currindex = currindex->next_currindex)
{
if(currindex->vnum == 0)
continue;
fprintf(fp, "#CURRINDEX\n");
fprintf(fp, "Vnum %d\n", currindex->vnum);
fprintf(fp, "Primary %d\n", currindex->primary);
fprintf(fp, "Name %s~\n", currindex->name);
fprintf(fp, "Charge %d\n", currindex->charge);
for(curr = currindex->first_currency; curr; curr = curr->next_currency)
{
fprintf(fp, "Currency %d %d %d\n", curr->tsiints, curr->type, curr->charge);
}
fprintf(fp, "End\n\n");
}
fprintf(fp, "#END\n");
FileClose(fp);
}
static void fread_currindex(CURR_INDEX_DATA * currindex, FILE * fp)
{
const char *word = NULL;
bool fMatch = FALSE;
for(;;)
{
word = feof(fp) ? "End" : fread_word(fp);
fMatch = FALSE;
switch (UPPER(word[0]))
{
case '*':
fMatch = TRUE;
fread_to_eol(fp);
break;
case 'E':
if(!str_cmp(word, "End"))
return;
break;
case 'C':
KEY("Charge", currindex->charge, fread_number(fp));
if(!str_cmp(word, "Currency"))
{
CURRENCY_DATA *curr;
curr = make_currency(currindex);
curr->tsiints = fread_number(fp);
curr->type = fread_number(fp);
curr->charge = fread_number(fp);
fMatch = TRUE;
break;
}
break;
case 'N':
KEY("Name", currindex->name, fread_string(fp));
break;
case 'P':
KEY("Primary", currindex->primary, fread_number(fp));
break;
case 'V':
KEY("Vnum", currindex->vnum, fread_number(fp));
break;
}
if(!fMatch)
{
bug("Fread_currency: no match: %s", word);
fread_to_eol(fp);
}
}
}
void load_currency(void)
{
FILE *fp;
CURR_INDEX_DATA *currindex;
bool found = FALSE;
init_mud_curr_index();
if((fp = FileOpen(CURRENCY_FILE, "r")) != NULL)
{
found = TRUE;
for(;;)
{
char letter;
char *word;
letter = fread_letter(fp);
if(letter == '*')
{
fread_to_eol(fp);
continue;
}
if(letter != '#')
{
bug("load_currency: # not found.");
break;
}
word = fread_word(fp);
if(!str_cmp(word, "CURRINDEX"))
{
currindex = make_currindex();
STRFREE(currindex->name);
fread_currindex(currindex, fp);
continue;
}
else if(!str_cmp(word, "END"))
break;
else
{
bug("load_currency: bad section.");
break;
}
}
FileClose(fp);
}
}
void do_listcurrency(CHAR_DATA *ch, char *argument)
{
CURR_INDEX_DATA *currindex;
CURRENCY_DATA *curr;
if(!first_curr_index)
{
send_to_char("There are no currencies.\r\n", ch);
return;
}
for(currindex = first_curr_index; currindex; currindex = currindex->next_currindex)
{
ch_printf(ch, "%-5d: %-41s Charge: %d%%\r\n", currindex->vnum, currindex->name, currindex->charge);
if(!currindex->first_currency)
send_to_char(" This curremcy index has no currency.\r\n", ch);
else
for(curr = currindex->first_currency; curr; curr = curr->next_currency)
ch_printf(ch, " %cCurrency: %-20s Tsiints: %-5d Charge: %d%%\r\n", curr->type == currindex->primary ? '*' : ' ', curr_types[curr->type], curr->tsiints, curr->charge);
}
}
void do_setcurrency(CHAR_DATA *ch, char *argument)
{
CURR_INDEX_DATA *currindex;
CURRENCY_DATA *curr;
char arg1[MIL], arg2[MIL], arg3[MIL], arg4[MIL];
if(!str_cmp(argument, "save"))
{
save_currency();
send_to_char("Ok.\r\n", ch);
return;
}
argument = one_argument(argument, arg1);
argument = one_argument(argument, arg2);
if(arg1[0] == '\0' || arg2[0] == '\0')
{
send_to_char("Syntax: setcurrency save\r\n", ch);
send_to_char("Syntax: setcurrency <currindex vnum> <field> [arguments]\r\n\r\n", ch);
send_to_char("Field being one of:\r\n create vnum name primary charge save delete\r\n", ch);
send_to_char("Field may also be a currency type:\r\n", ch);
send_to_char("Syntax: setcurrency <currindex vnum> <type> <field> [arguments]\r\n", ch);
send_to_char("Field being one of:\r\n tsiints charge delete\r\n", ch);
return;
}
if(!str_cmp(arg2, "create"))
{
int x = atoi(arg1);
if(find_currindex_vnum(x))
{
send_to_char("A currency index with that vnum already exists.\r\n", ch);
return;
}
currindex = make_currindex();
currindex->vnum = x;
if(argument && *argument != '\0')
{
if(currindex->name)
STRFREE(currindex->name);
currindex->name = STRALLOC(argument);
}
save_currency();
assign_currindex(get_room_index(currindex->vnum));
send_to_char("Ok.\r\n", ch);
return;
}
if(!(currindex = find_currindex_vnum(atoi(arg1))))
{
send_to_char("Unable to find that currindex.\r\n", ch);
return;
}
if(!str_cmp(arg2, "delete"))
{
free_currindex(currindex);
send_to_char("Ok.\r\n", ch);
return;
}
if(argument[0] == '\0')
{
do_setcurrency(ch, (char *)"");
return;
}
if(!str_cmp(arg2, "name"))
{
if(currindex->name)
STRFREE(currindex->name);
currindex->name = STRALLOC(argument);
send_to_char("Ok.\r\n", ch);
return;
}
argument = one_argument(argument, arg3);
if(!str_cmp(arg2, "primary"))
{
currindex->primary = get_currency_type(arg3);
for(curr = currindex->first_currency; curr; curr = curr->next_currency)
if(curr->type == currindex->primary)
break;
if(!curr || curr->type != currindex->primary)
{
currindex->primary = CURR_NONE;
send_to_char("Please use makecurrency before you set that as a primary.\r\n", ch);
return;
}
send_to_char("Ok.\r\n", ch);
return;
}
if(!str_cmp(arg2, "vnum"))
{
if(!is_number(arg3))
{
send_to_char("Vnum must be a number.\r\n", ch);
return;
}
if(find_currindex_vnum(atoi(arg3)))
{
send_to_char("There is another currindex with that vnum.\r\n", ch);
return;
}
currindex->vnum = atoi(arg3);
send_to_char("Ok.\r\n", ch);
return;
}
if(!str_cmp(arg2, "charge"))
{
currindex->charge = URANGE(0, atoi(arg3), 100);
send_to_char("Ok.\r\n", ch);
return;
}
if(!(curr = find_currency(currindex, get_currency_type(arg2))))
{
int type, x;
if((type = get_currency_type(arg2)) == CURR_NONE)
{
send_to_char("That is an invalid currency type.\r\n", ch);
return;
}
send_to_char("Creating currency.\r\n", ch);
x = atoi(arg1);
curr = make_currency(currindex);
curr->tsiints = x;
curr->type = type;
save_currency();
return;
}
if(!str_cmp(arg3, "delete"))
{
if(currindex->primary == curr->type)
{
send_to_char("Primary currency deleted.\r\n", ch);
currindex->primary = CURR_NONE;
}
free_currency(currindex, curr);
send_to_char("Ok.\r\n", ch);
return;
}
if(argument[0] == '\0')
{
do_setcurrency(ch, (char *)"");
return;
}
argument = one_argument(argument, arg4);
if(!is_number(arg4))
{
send_to_char("The fourth argument must be a number.\r\n", ch);
return;
}
if(!str_cmp(arg3, "tsiints"))
{
curr->tsiints = atoi(arg4);
send_to_char("Ok.\r\n", ch);
return;
}
if(!str_cmp(arg3, "charge"))
{
curr->charge = UMIN(atoi(arg4), 100);
send_to_char("Ok.\r\n", ch);
return;
}
do_setcurrency(ch, (char *)"");
}
void do_exchange(CHAR_DATA *ch, char *argument)
{
CHAR_DATA *keeper;
SHOP_DATA *pShop;
char arg1[MIL], arg2[MIL], arg3[MIL];
int value, newvalue = 0, change = 0;
int exchangetype = 0, newtype = 0;
pShop = NULL;
for(keeper = ch->in_room->first_person; keeper; keeper = keeper->next_in_room)
if(IS_NPC(keeper) && (pShop = keeper->pIndexData->pShop) != NULL)
break;
if((!pShop) && !IS_SET(ch->in_room->room_flags, ROOM_BANK))
{
send_to_char("You're not in a bank.\r\n", ch);
return;
}
argument = one_argument(argument, arg1);
argument = one_argument(argument, arg2);
argument = one_argument(argument, arg3);
if(!VLD_STR(arg1) || !VLD_STR(arg2) || !VLD_STR(arg3))
{
send_to_char("&CSyntax: exchange <amount> <cointype> <cointype>\r\n", ch);
send_to_char("&cExchange Rate\r\n", ch);
send_to_char("&COne Gold Coin = 10 Silver Coins\r\n", ch);
send_to_char("&COne Silver Coin = 10 Bronze Coins\r\n", ch);
send_to_char("&COne Bronze Coin = 10 Copper Coins\r\n", ch);
return;
}
value = atoi(arg1);
if(value <= 0)
{
send_to_char("Must use a number higher then 0.\r\n", ch);
return;
}
if(str_cmp(arg2, "gold") && str_cmp(arg2, "silver") && str_cmp(arg2, "bronze") && str_cmp(arg2, "copper"))
{
do_exchange(ch, (char *)"");
return;
}
if(str_cmp(arg3, "gold") && str_cmp(arg3, "silver") && str_cmp(arg3, "bronze") && str_cmp(arg3, "copper"))
{
do_exchange(ch, (char *)"");
return;
}
/*
* Go ahead and check values no point in going furthur if they dont have enough
*/
if(!str_cmp(arg2, "gold") && GET_MONEY(ch, CURR_GOLD) < value)
{
send_to_char("You don't have that much gold to exchange.\r\n", ch);
return;
}
else if(!str_cmp(arg2, "silver") && GET_MONEY(ch, CURR_SILVER) < value)
{
send_to_char("You don't have that much silver to exchange.\r\n", ch);
return;
}
else if(!str_cmp(arg2, "bronze") && GET_MONEY(ch, CURR_BRONZE) < value)
{
send_to_char("You don't have that much bronze to exchange.\r\n", ch);
return;
}
else if(!str_cmp(arg2, "copper") && GET_MONEY(ch, CURR_COPPER) < value)
{
send_to_char("You don't have that much copper to exchange.\r\n", ch);
return;
}
/*
* Lets get types etc...
*/
if(!str_cmp(arg2, "gold"))
exchangetype = CURR_GOLD;
else if(!str_cmp(arg2, "silver"))
exchangetype = CURR_SILVER;
else if(!str_cmp(arg2, "bronze"))
exchangetype = CURR_BRONZE;
else if(!str_cmp(arg2, "copper"))
exchangetype = CURR_COPPER;
if(!str_cmp(arg3, "gold"))
newtype = CURR_GOLD;
else if(!str_cmp(arg3, "silver"))
newtype = CURR_SILVER;
else if(!str_cmp(arg3, "bronze"))
newtype = CURR_BRONZE;
else if(!str_cmp(arg3, "copper"))
newtype = CURR_COPPER;
/*
* This would be pointless
*/
if(exchangetype == newtype)
{
send_to_char("No point in exchanging for the same kind of currency.\r\n", ch);
return;
}
/*
* Get how much newvalue would be
*/
if(!str_cmp(arg2, "gold"))
{
if(!str_cmp(arg3, "silver"))
{
newvalue = (value * 10);
change = (value - (newvalue / 10));
}
else if(!str_cmp(arg3, "bronze"))
{
newvalue = (value * 100);
change = (value - (newvalue / 100));
}
else if(!str_cmp(arg3, "copper"))
{
newvalue = (value * 1000);
change = (value - (newvalue / 1000));
}
}
else if(!str_cmp(arg2, "silver"))
{
if(!str_cmp(arg3, "gold"))
{
newvalue = (value / 10);
change = (value - (newvalue * 10));
}
else if(!str_cmp(arg3, "bronze"))
{
newvalue = (value * 10);
change = (value - (newvalue / 10));
}
else if(!str_cmp(arg3, "copper"))
{
newvalue = (value * 100);
change = (value - (newvalue / 100));
}
}
else if(!str_cmp(arg2, "bronze"))
{
if(!str_cmp(arg3, "gold"))
{
newvalue = (value / 100);
change = (value - (newvalue * 100));
}
else if(!str_cmp(arg3, "silver"))
{
newvalue = (value / 10);
change = (value - (newvalue * 10));
}
else if(!str_cmp(arg3, "copper"))
{
newvalue = (value * 10);
change = (value - (newvalue / 10));
}
}
else if(!str_cmp(arg2, "copper"))
{
if(!str_cmp(arg3, "gold"))
{
newvalue = (value / 1000);
change = (value - (newvalue * 1000));
}
else if(!str_cmp(arg3, "silver"))
{
newvalue = (value / 100);
change = (value - (newvalue * 100));
}
else if(!str_cmp(arg3, "bronze"))
{
newvalue = (value / 10);
change = (value - (newvalue * 10));
}
}
/*
* Make sure they would be gaining something
*/
if(newvalue <= 0)
{
send_to_char("Thats not enough to exchange.\r\n", ch);
return;
}
/*
* Take exchange currency
*/
GET_MONEY(ch, exchangetype) -= value;
/*
* Return any change
*/
if(change > 0)
GET_MONEY(ch, exchangetype) += change;
/*
* Give new currency
*/
GET_MONEY(ch, newtype) += newvalue;
ch_printf(ch, "You exchange %d %s coins for %d %s coins.\r\n", value, arg2, newvalue, arg3);
if(change > 0)
ch_printf(ch, "Your change of %d %s coins has been returned to you.\r\n", change, arg2);
return;
}
/* returns the cost of an object in currtype currency */
int obj_cost(ROOM_INDEX_DATA *room, OBJ_DATA *obj, int currtype)
{
return convert_curr(room, obj->cost, obj->currtype, currtype);
}
/* coins per pound */
const int money_weights[MAX_CURR_TYPE] = {
1, 1000, 1500, 2000, 750
};
int money_weight(int amount, int type)
{
return (amount / money_weights[type]);
}
int max_carry_money(CHAR_DATA *ch, int type)
{
int amount = can_carry_w(ch) - ch->carry_weight;
if(amount > 1000000)
return (1000000 * money_weights[type]);
return (amount * money_weights[type]);
}