#define __MONEY_CLASS__
#include <money.h>
#include <move_failures.h>
#include <obj_parser.h>
inherit OBJECT_OBJ;
private nosave int no_join;
private nosave int _already_joined;
private mixed money_array;
private nosave string _long;
void create() {
::create();
set_name("coin");
add_alias( MONEY_ALIAS );
add_plural("coins");
set_main_plural("coins");
add_property("determinate", "");
add_property("no one", 1 );
add_property("money", 1 );
money_array = ({ });
} /* create() */
/** @ignore yes */
int query_merger() { return 1; }
/** @ignore yes */
int query_no_join() { return no_join; }
/** @ignore yes */
int query_already_joined() { return _already_joined; }
/** @ignore yes */
void set_no_join() {
no_join = 1;
call_out("merge_coins", 0 );
} /* set_no_join() */
/** @ignore yes */
void reset_no_join() { no_join = 0; }
/**
* This method returns the number of coins in the object.
* @return the number of coins
*/
int query_number_coins() {
int i, tot;
if( _already_joined )
return 0;
for( i = 1; i < sizeof(money_array); i += 2 )
tot += money_array[ i ];
return tot;
} /* query_number_coins() */
/**
* This method fixes up the weight of the money object to be what it should
* be.
*/
void fixup_money_weight() {
float total;
int i;
for( i = 0; i < sizeof(money_array); i += 2 )
total += money_array[ i + 1 ] *
MONEY_H->query_weight_for( money_array[ i ] ) / 100.0;
if( total < 1 )
set_weight( 1 );
else
set_weight( to_int(total) );
} /* fixup_money_weight() */
/** @ignore yes */
int group_object() { return query_number_coins() > 1; }
/**
* This method goes through the coins and sets up all the adjectives
* and plurals it needs to.
*/
void check_adjectives() {
int i;
string *bits, *aliases;
set_adjectives( ({ }) );
set_aliases( ({ }) );
set_plurals( ({ }) );
if( !sizeof(money_array) ) {
_already_joined = 0;
move("/room/rubbish");
_already_joined = 1;
return;
}
add_alias(MONEY_ALIAS);
for( i = 0; i < sizeof(money_array); i += 2 ) {
aliases = MONEY_H->query_aliases_for( money_array[ i ] );
bits = explode( lower_case( money_array[ i ] ), " ");
if( sizeof(bits) > 1 ) {
add_adjective( bits[0..<2] );
if( sizeof( bits = explode( money_array[ i ], " ") - bits ) )
add_adjective( bits );
} else if( member_array( bits[0], aliases ) == -1 ) {
add_adjective( bits[0] );
}
add_alias( aliases );
add_plural( MONEY_H->query_plural_for( money_array[ i ] ) );
}
add_plural("coins");
} /* check_adjectives() */
/** @ignore yes */
mixed query_money_array() {
return ( !_already_joined ? money_array : ({ }) );
} /* query_money_array() */
/** @ignore yes */
varargs int adjust_money( mixed amount, string type, int internal ) {
int i, ret;
if( pointerp( amount ) ) {
for( i = 0; i < sizeof(amount); i += 2 )
adjust_money( amount[ i + 1 ], amount[ i ], 1 );
fixup_money_weight();
return 1;
}
if( !stringp(type) || !intp(amount) || _already_joined )
return 0;
short_d = _long = 0;
if( ( i = member_array( type, money_array ) ) == -1 ) {
string *aliases, *bits;
aliases = MONEY_H->query_aliases_for(type);
bits = explode( lower_case( type ), " ");
if( sizeof(bits) > 1 ) {
add_adjective( bits[0..<2] );
if( sizeof( bits = explode( type, " ") - bits ) )
add_adjective( bits );
} else if( member_array( bits[0], aliases ) == -1 ) {
add_adjective( bits[0] );
}
add_alias( aliases );
add_plural( lower_case( MONEY_H->query_plural_for(type) ) );
money_array += ({ type, amount });
ret = 1;
} else {
money_array[ i + 1 ] += amount;
if( money_array[ i + 1 ] <= 0 ) {
money_array = delete( money_array, i, 2 );
if( find_call_out("check_adjectives") == -1 )
call_out("check_adjectives", 0 );
ret = 0;
} else {
ret = 1;
}
}
if( !internal )
fixup_money_weight();
if( ret )
return money_array[ i + 1 ];
return 0;
} /* adjust_money() */
/** @ignore yes */
void set_money_array( mixed new_array ) {
short_d = _long = 0;
money_array = new_array;
fixup_money_weight();
if( find_call_out("check_adjectives") == -1 )
call_out("check_adjectives", 0 );
} /* set_money_array() */
/** @ignore yes */
string *half_short( int full ) {
int i;
string *retval;
retval = ({ });
for( i = 0; i < sizeof(money_array); i += 2 ) {
if( money_array[ i + 1 ] < 1 )
continue;
if( !full && ( money_array[ i + 1 ] > 12 ) ) {
retval += ({ "some "+
MONEY_H->query_main_plural_for( money_array[ i ] ) });
continue;
}
if( money_array[ i + 1 ] == 1 ) {
retval += ({ "one "+
MONEY_H->query_short_for( money_array[ i ] ) });
continue;
}
retval += ({ money_array[ i + 1 ] +" "+
MONEY_H->query_main_plural_for( money_array[ i ] ) });
}
return retval;
} /* half_short() */
/** @ignore yes */
string short( int dark ) {
string *retval;
if( short_d )
return short_d;
retval = half_short( 0 );
if( !sizeof( retval ) )
return 0;
if( sizeof( retval ) == 1 )
short_d = retval[ 0 ];
else
short_d = query_multiple_short( retval );
return short_d;
} /* short() */
/** @ignore yes */
string long( string word, int dark ) {
int i;
class money_data details;
if( dark < -1 )
return "It is too dark to see anything about the coins.\n";
if( dark > 1 )
return "It is too bright to see anything about the coins.\n";
if( _long )
return _long;
if( !sizeof( money_array ) )
return "This is some money that isn't money.\n";
_long = "";
for( i = 0; i < sizeof(money_array); i += 2 ) {
details = MONEY_H->query_details_for( money_array[i] );
_long += "Wrought from "+details->material+", the ";
if( money_array[i+1] == 1 )
_long += details->adj+" "+
MONEY_H->query_short_for( money_array[i] )+" shows ";
else
_long += query_num( money_array[i+1] )+" "+details->adj+" "+
MONEY_H->query_main_plural_for( money_array[i] )+" show ";
_long += details->head_long+" on the reverse, and "+
details->tail_long+" on the obverse.\n";
}
return _long;
} /* long() */
/** @ignore yes */
string query_long_details( string word, int dark, object looker ) {
if( dark < -1 )
return "It is too dark to see anything about the coins.\n";
if( dark > 1 )
return "It is too bright to see anything about the coins.\n";
return long( word, dark );
} /* query_long_details() */
/**
* This method creates a new money object from the current object. It uses
* the current objects values to make the money and removes the values from
* the coins.
* @param number the number of coins to remove
* @param type the type of coins to remove
* @return the new money object
*/
private object new_money_object( int number, string type, object money ) {
int i;
if( !sizeof( money_array ) || _already_joined )
return 0;
if( !type || type == "" )
return 0;
if( ( i = member_array( type, money_array ) ) == -1 )
return 0;
if( number > money_array[ i + 1 ] )
return 0;
if( !money )
money = clone_object(MONEY_OBJ);
money->set_no_join();
short_d = _long = 0;
// First we need to remove stuff from our array and update the weight,
// because otherwise add_weight() will not work in our container.
// If we adjust the weight of the newly created object first, we will
// end up with broken local weights in containers.
// This only happens with full containers or burdened players.
// - Sandoz.
money_array[ i + 1 ] -= number;
fixup_money_weight();
// This fixes up the weight of the new object as well.
money->adjust_money( number, type );
// Only now we try to move it, if it fails, move it to our room.
// This should help prevent broken local weights as well.
if( money->move( environment() ) ) {
object env, who;
if( env = ENV( who = environment() ) ) {
object tmp;
// Let's move us to the room, and give a message to
// the player whose inventory we are in.
while( tmp = ENV( env ) ) {
if( interactive(env) )
who = env;
env = tmp;
}
money->move(env);
tell_object( who, "Oh dear, "+money->the_short()+" refuse to fit "
"in "+environment()->the_short()+" any more and find their "
"way to "+env->the_short()+".\n");
}
}
if( money_array[ i + 1 ] < 1 ) {
// Remove the adjective right away so that we won't match on it again.
remove_adjective( money_array[ i ] );
money_array = delete( money_array, i, 2 );
if( find_call_out("check_adjectives") == -1 )
call_out("check_adjectives", 0 );
}
return money;
} /* new_money_object() */
/**
* This method merges two coin object together. Or attempts to anyway.
* This will occur whenever a coin object moves.
* @return the merged coin object
*/
object merge_coins() {
object money;
remove_alias(MONEY_ALIAS);
if( environment() )
money = present( MONEY_ALIAS, environment() );
if( objectp( money ) && money != TO && !_already_joined ) {
// First move us to the rubbish room to update the local weight of the
// container, then adjust the money array on the target money object.
// Otherwise we may end up with bad local weights again.
// - Sandoz.
set_no_join();
move("/room/rubbish");
_already_joined = 1;
money->adjust_money( money_array );
return money;
} else {
add_alias( MONEY_ALIAS );
}
return TO;
} /* merge_coins() */
/** @ignore yes */
varargs int move( mixed dest, string messin, string messout ) {
int i;
if( _already_joined )
return MOVE_INVALID_DEST;
i = ::move( dest, messin, messout );
if( i != MOVE_OK )
return i;
if( file_name( environment() ) == "/room/rubbish" || no_join )
reset_no_join();
else
merge_coins();
return MOVE_OK;
} /* move() */
/** @ignore yes */
public varargs mixed find_best_fit( mixed word, int flag ) {
int i, best, best_rating, rating;
string against, *words, *arr;
if( !word || word == "")
return 0;
if( stringp(word) )
words = explode( lower_case( word ), " ") - ({"coin", "coins"});
else
words = word;
if( flag )
arr = ({ });
best = -1;
for( i = 0; i < sizeof( money_array ); i += 2 ) {
rating = 0;
against = "X "+lower_case( replace( money_array[ i ] +" "+
MONEY_H->query_plural_for( money_array[ i ] ), " coins", "") )+" X";
foreach( word in words ) {
if( sscanf( against, "%*s "+lower_case(word)+" %*s") == 2 )
rating++;
}
if( flag && rating >= best_rating )
arr += ({ money_array[i] });
if( rating > best_rating ) {
best_rating = rating;
best = i;
if( flag )
arr = ({ money_array[i] });
}
}
if( flag )
return arr;
return best;
} /* find_best_fit() */
/** @ignore yes */
object query_parse_id( mixed arr ) {
int i;
string *bits;
object money;
if( arr[ 0 ] < 0 || !sizeof( money_array ) )
return 0;
if( arr[ 0 ] == 0 ) {
bits = explode( arr[ 1 ], " ");
if( sizeof(bits) == 1 && bits[ 0 ] == "coins")
return TO;
if( member_array( bits[<1], query_plurals() ) == -1 )
return TO;
if( ( i = find_best_fit( arr[ 1 ] ) ) == -1 )
return 0;
money = new_money_object( money_array[ i + 1 ], money_array[ i ], 0 );
return money;
}
// Not very satisfactory.
if( ( i = find_best_fit( arr[ 1 ] ) ) == -1 )
i = 0;
if( arr[ 0 ] > money_array[ i + 1 ] )
return 0;
money = new_money_object( arr[ 0 ], money_array[ i ], 0 );
return money;
} /* query_parse_id() */
/** @ignore yes */
mixed parse_match_object( string *input, object viewer,
class obj_match_context context ) {
int ret, num, every;
mixed found;
object ob;
if( !sizeof(money_array) )
return 0;
if( !ret = ::is_matching_object( input, viewer, context ) )
return 0;
if( sizeof(input) == 1 && !context->number_included && !context->ordinal ) {
if( input[<1] == "coins" || input[<1] == "money" || input[<1] == "all")
return ({ OBJ_PARSER_MATCH_PLURAL, ({ TO }) });
if( input[<1] == "coin") {
// Only one coin.
if( sizeof( money_array ) == 2 && money_array[ 1 ] == 1 )
return ({ OBJ_PARSER_MATCH_PLURAL, ({ TO }) });
// Pick the first coin, any coin...
if( !num = update_parse_match_context( context, 1, ret ) )
return 0;
if( !ob = new_money_object( num, money_array[ 0 ], 0 ) )
return 0;
return ({ ret, ({ ob }) });
}
}
every = context->number_included == EVERY_NUM;
if( sizeof(input) == 1 && input[<1] == "coin") {
// We matched on "every coin".
if( every )
return ({ ret, ({ TO }) });
// Make it the first random coin.
input[<1] = money_array[ 0 ];
}
if( every || ( !context->number_included && input[<1] == "coins") ) {
if( sizeof( found = find_best_fit( input, 1 ) ) ) {
foreach( string str in found ) {
int i;
// Lets see how many we have...
i = member_array( str, money_array );
num = money_array[ i + 1 ];
if( num = update_parse_match_context( context, num, ret ) ) {
ob = new_money_object( num, str, ob );
// Do this so that we keep matching on the rest as well.
if( every )
context->number_included = EVERY_NUM;
}
}
}
if( ob )
return ({ ret, ({ ob }) });
}
if( ( found = find_best_fit(input) ) == -1 )
return 0;
// Lets see how many we have...
num = money_array[ found + 1 ];
if( !num = update_parse_match_context( context, num, ret ) )
return 0;
if( !ob = new_money_object( num, money_array[found], 0 ) )
return 0;
return ({ ret, ({ ob }) });
} /* parse_match_object() */
/** @ignore yes */
int do_not_sell() { return 1; }
/** @ignore yes */
int query_value() { return 0; }
/** @ignore yes */
int query_value_in( string where ) {
return MONEY_H->query_total_value( money_array, where );
} /* query_value_in() */
/**
* This method returns the amount of type of money there is in the array.
* @param type the type of money to check
* @return the number of coins of that type
*/
int query_money( string type ){
int i;
if( ( i = member_array( type, money_array ) ) == -1 )
return 0;
return money_array[i+1];
} /* query_money () */
/** @ignore yes */
mapping query_dynamic_auto_load() {
if( !_already_joined ) {
return ([
"::" : ::query_dynamic_auto_load(),
"money array" : money_array,
]);
}
} /* query_dynamic_auto_load() */
/** @ignore yes */
void init_dynamic_arg( mapping map ) {
::init_dynamic_arg( map["::"] );
set_money_array( map["money array"] );
} /* init_dynamic_arg() */