lima-1.0b5/
lima-1.0b5/driver/
lima-1.0b5/driver/ChangeLog.old/
lima-1.0b5/driver/Win32/
lima-1.0b5/driver/compat/
lima-1.0b5/driver/include/
lima-1.0b5/driver/testsuite/
lima-1.0b5/driver/testsuite/clone/
lima-1.0b5/driver/testsuite/command/
lima-1.0b5/driver/testsuite/data/
lima-1.0b5/driver/testsuite/etc/
lima-1.0b5/driver/testsuite/include/
lima-1.0b5/driver/testsuite/inherit/
lima-1.0b5/driver/testsuite/inherit/master/
lima-1.0b5/driver/testsuite/log/
lima-1.0b5/driver/testsuite/single/
lima-1.0b5/driver/testsuite/single/tests/compiler/
lima-1.0b5/driver/testsuite/single/tests/efuns/
lima-1.0b5/driver/testsuite/single/tests/operators/
lima-1.0b5/driver/testsuite/u/
lima-1.0b5/driver/tmp/
lima-1.0b5/etc/
lima-1.0b5/lib/WWW/help/
lima-1.0b5/lib/cmds/
lima-1.0b5/lib/cmds/create/
lima-1.0b5/lib/cmds/player/attic/
lima-1.0b5/lib/contrib/bboard/
lima-1.0b5/lib/contrib/boards/
lima-1.0b5/lib/contrib/marriage/
lima-1.0b5/lib/contrib/roommaker/
lima-1.0b5/lib/contrib/transient_effect/
lima-1.0b5/lib/daemons/channel/
lima-1.0b5/lib/daemons/imud/
lima-1.0b5/lib/data/
lima-1.0b5/lib/data/config/
lima-1.0b5/lib/data/links/
lima-1.0b5/lib/data/news/
lima-1.0b5/lib/data/players/
lima-1.0b5/lib/data/secure/
lima-1.0b5/lib/domains/
lima-1.0b5/lib/domains/std/2.4.5/maze1/
lima-1.0b5/lib/domains/std/2.4.5/npc/
lima-1.0b5/lib/domains/std/2.4.5/post_dir/
lima-1.0b5/lib/domains/std/2.4.5/sub/
lima-1.0b5/lib/domains/std/camera/
lima-1.0b5/lib/domains/std/config/
lima-1.0b5/lib/domains/std/cult/
lima-1.0b5/lib/domains/std/effects/
lima-1.0b5/lib/domains/std/misc/
lima-1.0b5/lib/domains/std/monsters/
lima-1.0b5/lib/domains/std/recorder/
lima-1.0b5/lib/domains/std/rooms/
lima-1.0b5/lib/domains/std/rooms/beach/
lima-1.0b5/lib/domains/std/rooms/labyrinth/
lima-1.0b5/lib/domains/std/school/
lima-1.0b5/lib/domains/std/school/O/
lima-1.0b5/lib/domains/std/spells/
lima-1.0b5/lib/domains/std/spells/stock-mage/
lima-1.0b5/lib/domains/std/spells/stock-priest/
lima-1.0b5/lib/help/
lima-1.0b5/lib/help/admin/
lima-1.0b5/lib/help/hints/General_Questions/
lima-1.0b5/lib/help/hints/Pirate_Quest/
lima-1.0b5/lib/help/player/
lima-1.0b5/lib/help/player/bin/
lima-1.0b5/lib/help/player/quests/
lima-1.0b5/lib/help/wizard/
lima-1.0b5/lib/help/wizard/coding/guilds/
lima-1.0b5/lib/help/wizard/coding/rooms/
lima-1.0b5/lib/help/wizard/lib/daemons/
lima-1.0b5/lib/help/wizard/lib/lfun/
lima-1.0b5/lib/help/wizard/lib/std/
lima-1.0b5/lib/help/wizard/mudos_doc/
lima-1.0b5/lib/help/wizard/mudos_doc/applies/
lima-1.0b5/lib/help/wizard/mudos_doc/applies/interactive/
lima-1.0b5/lib/help/wizard/mudos_doc/applies/parsing/
lima-1.0b5/lib/help/wizard/mudos_doc/concepts/
lima-1.0b5/lib/help/wizard/mudos_doc/driver/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/arrays/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/buffers/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/compile/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/filesystem/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/floats/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/functions/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/general/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/mappings/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/mixed/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/numbers/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/parsing/
lima-1.0b5/lib/help/wizard/mudos_doc/lpc/constructs/
lima-1.0b5/lib/help/wizard/mudos_doc/lpc/types/
lima-1.0b5/lib/include/driver/
lima-1.0b5/lib/log/
lima-1.0b5/lib/obj/admtool/
lima-1.0b5/lib/obj/admtool/internal/
lima-1.0b5/lib/obj/admtool/mudinfo/
lima-1.0b5/lib/obj/admtool/secure/
lima-1.0b5/lib/obj/secure/
lima-1.0b5/lib/obj/secure/cmd/
lima-1.0b5/lib/obj/secure/mailers/
lima-1.0b5/lib/obj/secure/shell/
lima-1.0b5/lib/obj/secure/shell/classes/
lima-1.0b5/lib/obj/tasktool/
lima-1.0b5/lib/obj/tasktool/internal/
lima-1.0b5/lib/open/
lima-1.0b5/lib/secure/
lima-1.0b5/lib/secure/cgi/
lima-1.0b5/lib/secure/modules/
lima-1.0b5/lib/secure/simul_efun/
lima-1.0b5/lib/std/adversary/
lima-1.0b5/lib/std/adversary/advancement/
lima-1.0b5/lib/std/adversary/armor/
lima-1.0b5/lib/std/adversary/blows/
lima-1.0b5/lib/std/adversary/death/
lima-1.0b5/lib/std/adversary/formula/
lima-1.0b5/lib/std/adversary/health/
lima-1.0b5/lib/std/adversary/pulse/
lima-1.0b5/lib/std/adversary/wield/
lima-1.0b5/lib/std/classes/event_info/
lima-1.0b5/lib/std/container/
lima-1.0b5/lib/std/living/
lima-1.0b5/lib/std/modules/contrib/
lima-1.0b5/lib/std/patterns/
lima-1.0b5/lib/std/race/
lima-1.0b5/lib/std/race/restricted/
lima-1.0b5/lib/std/room/
lima-1.0b5/lib/tmp/
lima-1.0b5/lib/trans/
lima-1.0b5/lib/trans/admincmds/
lima-1.0b5/lib/trans/obj/
lima-1.0b5/lib/wiz/
/* Do not remove the headers from this file! see /USAGE for more info. */

/*
** money_d.c -- money daemon
**
** This daemon manages the legal types of money within the game and their
** exchange rates.
**
** Objects have an inherent "value".  This is then translated into a
** particular currency via that currency's value -> actual exchange rate.
**
** Currencies have different denomiations, e.g. dollar have dollar and cent.
** Calculation is always based on the lowest denomination. Functions for
** displaying a currency with denominations are provided
**
** Created Wed Jul  3 20:28:42 MET DST 1996 <Valentino>
**
** 961209, Deathblade: Revised extensively and installed into Lima.
**                     Kept Valentino's per-area currencies, but tossed
**                        the materials concept.
**
** rewritten 10 Feb 98 by MonicaS, removed per-area currencies, added
**        denominations
*/

inherit M_DAEMON_DATA;

class denomination {
  float factor;
  string plural;
  string currency;
}

//Mapping of currency names to unit values.  A given currency is worth
//this many "units," which is used for conversion purposes.
private mapping rates = ([ ]);

//Mapping of currency names to plural of the names
private mapping plurals = ([ ]);

//Mapping of currency names to sorted array of denomination names
private mapping denominations = ([ ]);

//Mapping of denomination name to class denomination
private mapping denomination = ([ ]);

//Mapping of plural names to singular names
nosave mapping singulars = ([ ]);

//:FUNCTION singular_name
//singular_name returns the canonical name for a denomination/currency
//e.g. lover case, without spaces and singular.
string singular_name(string name) {
  name = lower_case(trim_spaces(name));
  if (singulars[name])
    name = singulars[name];
  return name;
}

//:FUNCTION query_exchange_rate
//Returns the exchange rate to map from an object's inherent value to its
//actual value in a particular currency.  The value returned is the number
//of units this currency is worth.
nomask int query_exchange_rate(string type) {
  return rates[singular_name(type)];
}

//:FUNCTION query_currency_types
//Returns the names of the currencies that are valid within the mud
nomask string *query_currency_types() {
  return keys(denominations);
}

//:FUNCTION query_denominations
//Returns the array of denominations of a currency 
//or all available denominations
varargs nomask string array query_denominations(string type) {
  if (type) {
    return denominations[singular_name(type)];
  } 
  else
    return keys(denomination);
}

//:FUNCTION is_currency
//tests if name is a currency
nomask int is_currency(string name) {
  return denominations[singular_name(name)] != 0;
}

//:FUNCTION is_denomination
//tests if name is a denomination
nomask int is_denomination(string name) {
  return denomination[singular_name(name)] != 0;
}

//:FUNCTION query_currency
//Returns the currency of a denomination
nomask string query_currency(string name) {
  name = singular_name(name);
  if (!denomination[name])
    error("unknown denomination: "+name+".\n");
  return denomination[name]->currency;
}

//:FUNCTION query_plural
//Returns the plural name of a denomination
nomask string query_plural(string name) {
  name = singular_name(name);
  if (denomination[name])
    return denomination[name]->plural;
  if (denominations[name]) //test if currency
    if (plurals[name])
      return plurals[name];
    else
      return M_GRAMMAR->pluralize(name);
  error("unknown denomination/currency: "+name+".\n");
}

//:FUNCTION query_factor
//Returns the exchange rate factor of a denomination
nomask float query_factor(string name) {
  name = singular_name(name);
  if (!denomination[name])
    error("unknown denomination: "+name+".\n");
  return denomination[name]->factor;
}

//:FUNCTION add_currency
//Add a currency to the money system. The base denomination with the same 
//name will be created too if flag is 0.
varargs nomask void add_currency(string type, string plural, int flag) {
  if (!check_privilege("Mudlib:daemons"))
    error("illegal attempt to add a currency.\n");
  type = lower_case(trim_spaces(type));
  if (plural)
    plural = lower_case(plural);
  else
    plural = M_GRAMMAR->pluralize(type);
  plurals[type] = plural;
  singulars[plural] = type;
  //if the currency already exists only set plural
  if (!denominations[type]) {
    rates[type] = 1000;
    if (!flag) {
      denomination[type] = new(class denomination, currency: type, 
			       plural: plural, factor: 1.0);
      denominations[type] = ({ type });
    }
  }
  save_me();
}

//:FUNCTION remove_currency
//Removes a currency from the money system.
nomask void remove_currency(string type) {
  if (!check_privilege("Mudlib:daemons"))
    error("illegal attempt to add a currency.\n");
  type = singular_name(type);
  if (!denominations[type])
    error("illegal currency type: "+type+"\n");
  foreach (string name in denominations[type]) {
    map_delete(denomination, name);
  }
  map_delete(denominations, type);
  map_delete(rates, type);
  map_delete(singulars, plurals[type]);
  map_delete(plurals, type);
  save_me();
}

//:FUNCTION set_exchange_rate
//Set the exchange rate (that is the value) of a currency
nomask void set_exchange_rate(string type, int rate) {
  if (!check_privilege("Mudlib:daemons"))
    error("illegal attempt to adjust exchange rate.\n");
  type = singular_name(type);
  if (!denominations[type])
    error("illegal currency type: "+type+"\n");  
  if (rate == 0)
    remove_currency(type);
  else
    rates[type] = rate;
  save_me();
}

//denominations have to be sorted in reverse order, so that evaluation
//in currency_to_string() works.
private int compare_denominations(string d1, string d2) {
  if (denomination[d1]->factor > denomination[d2]->factor) 
    return -1;
  else 
    return (denomination[d1]->factor < denomination[d2]->factor);
}

//:FUNCTION add_denomination
//add a denomination to a currency
void add_denomination(string type, string name, string plural, float factor) {
  if (!check_privilege("Mudlib:daemons"))
    error("illegal attempt to add a denomination.\n");
  type = singular_name(type);
  name = lower_case(trim_spaces(name));
  if (denomination[name] && denomination[name]->currency != type)
    error("denomination "+name+" already exists in currency "
	  +denomination[name]->currency+"\n");
  plural = lower_case(plural);
  singulars[plural] = name;
  denomination[name] = new(class denomination, currency: type, 
			   plural: plural, factor: factor);
  if (!denominations[type]) {
    if (type == name)
      add_currency(type, plural, 1);
    else
      add_currency(type, 0, 1);
    denominations[type] = ({ name });
  }
  else {
    denominations[type] |= ({ name });
    denominations[type] = sort_array(denominations[type],
				     (: compare_denominations :) );
  }
  save_me();
}

//:FUNCTION remove_denomination
//removes a denomination from a currency
void remove_denomination(string name) {
  string type;

  if ( !check_privilege("Mudlib:daemons") )
    error("illegal attempt to removes a denomination.\n");
  name = singular_name(name);
  if (!denomination[name])
    error("unknown denomination: "+name+"\n");
  type = denomination[name]->currency;
  if (sizeof(denominations[type]) == 1)
    remove_currency(type);
  else {
    denominations[type] -= ({ name });
    if (!denominations[name])
      map_delete(singulars, denomination[name]->plural);
    map_delete(denomination, name);
    save_me();
  }
}

//:FUNCTION denomination_to_string
//create a string with correct use of plural from an amount of a denomination.
nomask string denomination_to_string(int amount, string type) {
  type = singular_name(type);
  if (!denomination[type])
    error("illegal denomination: "+type+"\n");
  if (amount > 1)
    return amount+" "+denomination[type]->plural;
  else
    return amount+" "+type;
}

//:FUNCTION calculate_denominations
//calculate denominations which add up to a certain amount.
mapping calculate_denominations(float f_amount, string currency) {
  mapping money = ([ ]);
  int amount;
  
  currency = singular_name(currency);
  if (!denominations[currency])
    error("illegal currency type: "+currency+"\n");  
  // avoid rounding errors
  f_amount += denomination[denominations[currency][<1]]->factor * 0.1;
  foreach (string type in denominations[currency]) {
    amount = to_int(f_amount / denomination[type]->factor);
    if (amount) {
      f_amount -= to_float(amount) * denomination[type]->factor;
      money[type] = amount;
    }
  }
  return money;
}

//:FUNCTION currency_to_string
//create a string with denominations from an amount of money.
//The money is a mapping from denomination to amount or a float.
//If the currency is not 0 only money of that type of currency is regarded.
//The output is only sorted if you specify the currency.
varargs nomask string currency_to_string(mixed money, string currency) {
  int amount;
  string name, str = "";
  string array types;
  
  if (currency) {
    currency = singular_name(currency);
    if (!denominations[currency])
      error("illegal currency type: "+currency+"\n");
    if (!mapp(money))
      money = calculate_denominations(money, currency);
    types = denominations[currency];
  }
  else {
    types = keys(money);
  }

  foreach (name in types) {
    if (amount = money[name]) {
      if (str != "")
	str += ", ";
      if (amount > 1)
	str += amount+" "+denomination[name]->plural;
      else
	str += amount+" "+name;
    }
  }
  if (str == "")
    if (currency)
      str = "no "+query_plural(currency);
    else
      str = "no money";
  return str;
}

//:FUNCTION handle_subtract_money
//substracts an amount of currency from a player and adds change.
//returns an array of two mappings: substract and change, which
//consist of the denominations which were used.
mapping array handle_subtract_money(object player, float f_amount, 
				     string type) {
  mapping substract = ([ ]), change;
  int amount;

  type = singular_name(type);
  if (is_currency(type)) {
    
    mapping money = player->query_money();
    string array types = denominations[type];
    string currency = type;
    for (int i = sizeof(types) - 1; i >= 0; i--) {
      type = types[i];
      amount = to_int(f_amount / denomination[type]->factor + 0.9999);
      if (amount <= money[type]) {
	substract[type] = amount;
	f_amount -= to_float(amount) * denomination[type]->factor;
	break;
      }
    }
    if (f_amount > 0) {
      foreach (type in types) {
	amount = to_int(f_amount / denomination[type]->factor + 0.9999);
	if (amount > money[type]) {
	  substract[type] = money[type];
	  f_amount -= to_float(money[type]) * denomination[type]->factor;
	}
	else {
	  substract[type] = amount;
	  f_amount -= to_float(amount) * denomination[type]->factor;
	  break;
	}
      }
    }
    change = calculate_denominations(-f_amount, currency);
  }
  else {
    string currency = query_currency(type);
    amount = to_int(f_amount + 0.9999);
    substract[type] = amount;
    f_amount = (to_float(amount) - f_amount) * denomination[type]->factor;
    change = calculate_denominations(f_amount, currency);
  }
  foreach (type, amount in substract) {
//Because of the floats we sometimes get rounding errors,
//so let's clean up a little.
    if (change[type]) {
      change[type]--;
      substract[type]--;
    }
    player->subtract_money(type, amount);
  }
  foreach (type, amount in change) {
    player->add_money(type, amount);
  }
  return ({ substract, change });
}

create() {
  ::create();
  foreach (string type, string plural in plurals) {
    singulars[plural] = type;
  }
  foreach (string type, class denomination d in denomination) {
    singulars[d->plural] = type;
  }
}

void clean_up() {
  destruct();
}