/* A basic fence for thieves and others to sell stolen items to. */ #include <armoury.h> #include <money.h> #include <move_failures.h> #include <thief.h> inherit "/obj/monster"; #define MAX 500 #define SKILL "other.trading.valueing" #define PAY_RATES ({ 200, 95, \ 400, 90, \ 800, 85, \ 1600, 80, \ 3200, 75, \ 6400, 70, \ 12800, 65, \ 60 }) class hist_offer { object ob; int old_offer; int value; } class offer { object who; int amount; int offer_time; object *objects; } class offer this_offer; object cont; string *move_data = ({ }); string fence_type; mapping old_offers = ([ ]); void whisper( object, string ); void give_back(); object query_cont() { return cont; } void create() { do_setup++; ::create(); do_setup--; if( !do_setup ) this_object()->setup(); // Give him his bag. cont = clone_object( "/std/container" ); cont->move(this_object()); cont->reset_drop(); cont->reset_get(); cont->set_name( "sack" ); cont->set_short( "sack" ); cont->set_long( "This is a large hessian sack.\n" ); cont->add_property( "nosteal", 1 ); set_wimpy( 20 ); basic_setup( "human", "thief", 500 ); add_respond_to_with( ({ "@say", ({ "yes", "Yes", "ok", "okay" }) }), "#do_yes" ); add_respond_to_with( ({ "@nod", ({ "you" }) }), "#do_yes" ); add_respond_to_with( ({ "@whisper", ({ "yes", "Yes", "ok", "okay" }) }), "#do_yes" ); add_respond_to_with( ({ "@say", ({ "no", "No" }) }), "#do_no" ); add_respond_to_with( ({ "@whisper", ({ "no", "No" }) }), "#do_no" ); add_respond_to_with( ({ "@shake", ({ "you" }) }), "#do_no" ); } void init() { ::init(); this_player()->add_command( "fence", this_object(), "<indirect:object:me> to <direct:object>" ); } void dest_me() { if( cont ) cont->dest_me(); ::dest_me(); } void reset() { object ob; // Don't dest anything if we're in the middle of dealing with someone. if( this_offer ) return; foreach( ob in all_inventory( cont ) ) ob->dest_me(); } void check_cont() { if ( !cont ) cont = clone_object( "/std/container" ); } void set_fence_type( string str ) { fence_type = str; } int query_cost( object thing, object buyer ) { return (int)thing->query_value_at( this_object() ); } string cost_string( object thing, string place, object buyer ) { return (string)MONEY_HAND->money_value_string( query_cost( thing, buyer ), place ); } // Determine item type string query_item_type( object ob ) { if( member_array( "weapons", ob->query_plurals()) != -1 ) return "weapons"; if( member_array( "jewellery", ob->query_plurals()) != -1 || ob->query_property( "shop type" ) == "jewellers" ) return "jewellery"; if( member_array( "armours", ob->query_plurals()) != -1 ) return "armour"; if( member_array( "clothes", ob->query_plurals()) != -1 ) return "armour"; if( member_array( "gems", ob->query_plurals()) != -1 ) return "gems"; return ""; } // Judge the value of an item int judge_value( object ob, string type ) { int value, variance, skill; value = query_cost( ob, this_object() ); if( type != "" ) skill = query_skill_bonus( SKILL + "." + type ); else skill = query_skill_bonus( SKILL ); if( !skill ) skill = 1; variance = value / sqrt( skill ); value += random( variance ) - random( variance ); return value; } // Work out where we are (for money strings) Make the default AM. string calc_place() { string place; place = environment()->query_property( "place" ); if( !place || ( place == "" ) ) place = "Ankh-Morpork"; return place; } // Return an amount of money as a nice string string cost_str( int amt ) { return MONEY_HAND->money_string( MONEY_HAND->create_money_array( amt, calc_place() ) ); } // From /std/shop. int scaled_value( int n ) { int *fish, i, tot; fish = PAY_RATES; if( n < fish[0] ) { return n; } else { tot = fish[0]; n -= fish[0]; } i = 0; while( n && ( ( i + 1 ) < sizeof( fish ) ) ) { if( n >= fish[i]) { tot += fish[i+1] * fish[i] / 100; n -= fish[i]; } else { tot += fish[i+1] * n / 100; n = 0; } i += 2; } if( n ) { tot += ( n * fish[sizeof( fish ) - 1] ) / 100; } return tot; } /* scaled_value() */ int do_fence( object *in_dir, string direct, string indirect, mixed args, string format ) { int offer, their_skill, returned, burdened, light; string type, skill, zone; object ob, *offered, *not_speciality, customer, thing; if( !this_player()->query_creator() && !this_player()->query_visible( this_object() ) ) { this_object()->do_command( "puzzle" ); this_object()->do_command( "wonder if someone is trying to be funny" ); return 0; } light = environment( this_object() )->query_light(); if ( ( light < 20 ) || ( light > 100 ) ) { if ( light > 100 ) { this_object()->do_command( "say I can't see anything in the glare!" ); } else { this_object()->do_command( "say I can't see anything in the gloom!" ); } return 0; } if( this_offer && this_offer->who && environment( this_offer->who ) == environment( this_object() ) ) { if( this_offer->offer_time > time() - 30 ) { if( this_offer->who != this_player() ) whisper( this_player(), "Sorry, I'm already helping " + ( this_offer->who )->the_short() + "." ); else whisper( this_player(), "I'm still waiting for a response from you!" ); this_player()->add_succeeded_mess( this_object(), "", offered ); return 1; } else { // Lets return the items coz they didn't answer in time. whisper( this_offer->who, "I guess you don't want my offer then." ); customer = this_offer->who; burdened = 0; returned = 0; foreach( thing in this_offer->objects ) { // Sometimes the items turn into 0s. if( !thing ) { whisper( customer, "Seems there is a hole in my sack!" ); continue; } if( thing->move( customer ) != MOVE_OK ) { burdened = 1; thing->move( environment( this_object() ) ); whisper( customer, "I'll just put the " + thing->short() + " down here since you are too burdened to accept it." ); } else { returned = 1; } } if( burdened && returned ) { tell_object( customer, this_object()->a_short() + " returns the other " "items to you.\n" ); } else { if( returned ) tell_object( customer, this_object()->a_short() + " returns the " "items to you.\n" ); } tell_room( environment(), this_object()->a_short() + " returns the " "items to " + customer->a_short() + ".\n", ({ customer }) ); this_offer = 0; } } not_speciality = ({ }); if( sizeof( this_object()->query_move_zones() ) ) { foreach( zone in this_object()->query_move_zones() ) { move_data += ({zone}); this_object()->remove_move_zone(zone); } this_object()->add_move_zone( 0 ); } this_offer = new( class offer, objects : ({ }), who : this_player(), offer_time : time() ); in_dir = filter_array( in_dir, (: !$1->query_keep() :) ); if( sizeof( in_dir ) < 1 ) { whisper( this_player(), "You have nothing to fence that you're not overly " "fond of, it seems." ); this_player()->add_succeeded_mess( this_object(), "", offered ); this_offer = 0; return 1; } if( sizeof( in_dir ) > 10 ) { whisper( this_player(), "Sorry, I can't handle that many items at " "once." ); this_player()->add_succeeded_mess( this_object(), "", offered ); this_offer = 0; return 1; } tell_room( environment( this_object() ), this_object()->query_short() + " studies " + query_multiple_short( in_dir ) + ".\n" ); foreach( ob in in_dir ) { // Player doesn't have item. if( environment( ob ) != this_offer->who ) { whisper( this_player(), "Do you think I'm blind? I can see that you " "don't have " + strip_colours( ob->the_short()) + "." ); continue; } if( base_name(ob) == "/obj/money" ) { whisper( this_player(), "I don't accept coins, I'm afraid. The market " "fluctuates far too much for it to be worthwhile."); continue; } // Can't move to sack. if( ob->move( cont ) != MOVE_OK ) { whisper( this_player(), "If I can't take an item you can't fence it " "so you can't fence " + strip_colours( ob->the_short()) + "." ); continue; } // Item have do_not_sell on it. if( ob->do_not_sell() ) { whisper( this_player(), "You can't sell the " + strip_colours( ob->the_short() ) + "." ); if( ob->move( this_player() ) != MOVE_OK ) { ob->move( environment( this_object() ) ); whisper( this_player(), "So I'll just put it down here." ); } else { whisper( this_player(), "So you can have it back." ); } continue; } if( ob->query_property( "fenced" ) ) { do_command( "' Hang on a sec... this looks awful familiar." ); do_command( "glare " + this_offer->who->query_name() ); do_command( "' Just what are you trying to pull here?!" ); do_command( "' I think I'll hang onto these little trinkets " "until we can establish their correct ownership..." ); // Annulling the offer effectively confiscates their crap. this_offer = 0; this_player()->add_failed_mess( this_object(), this_object()-> the_short() + " confiscates $I.\n", in_dir ); return 0; } type = query_item_type( ob ); offer = judge_value( ob, type ); // Item not worth anything or smaller than a pence. if( !offer || offer < 4 ) { whisper( this_player(), ob->the_short() + " isn't worth anything." ); if( ob->move( this_player() ) != MOVE_OK ) { ob->move( environment( this_object() ) ); whisper( this_player(), "So I'll just put it down here." ); } else { whisper( this_player(), "So you can have it back." ); } continue; } // Are we a fence for this type of object? if( type != fence_type ) { offer -= ( offer / 10 ); not_speciality += ({ ob }); } // Now do the profit (just like a shop) offer = (int)scaled_value( offer ); // Remember our previous offers. if( !undefinedp( old_offers[ob] ) ) { if( !undefinedp( old_offers[ob][ob->query_value()] ) ) { // Found it offer = old_offers[ob][ob->query_value()]; } else { old_offers[ob][ob->query_value()] = offer; } } else { old_offers[ob] = ([ ob->query_value() : offer ]); } // Now see if we can fleece them if( type != "" ) skill = SKILL + "." + type; else skill = SKILL; their_skill = this_player()->query_skill_bonus( skill ); if( !their_skill) their_skill = 2; // Reduce the offer dependant on their valueing skill if( sqrt( their_skill ) < 3 ) offer -= offer / 3; else { offer -= ( offer ) / sqrt( their_skill ); } // Item not worth anything after all the adjustments. if( !offer || offer < 4 ) { whisper( this_player(), ob->the_short() + " isn't worth anything." ); if( ob->move( this_player() ) != MOVE_OK ) { ob->move( environment( this_object() ) ); whisper( this_player(), "So I'll just put it down here." ); } else { whisper( this_player(), "So you can have it back." ); } continue; } this_offer->amount += offer; this_offer->objects += ({ ob }); } if( sizeof( not_speciality ) == 1 ) whisper( this_player(), "Well, " + strip_colours( query_multiple_short( not_speciality ) ) + " isn't really " "my speciality." ); else if( sizeof( not_speciality ) > 1 ) whisper( this_player(), "Well, " + strip_colours( query_multiple_short( not_speciality ) ) + " aren't " "really my speciality." ); this_player()->add_succeeded_mess( this_object(), "", offered ); if( !sizeof( this_offer->objects ) ) { whisper( this_player(), "Well, that was a waste of time." ); this_offer = 0; return 1; } // Tell em how much and wait for their response whisper( this_player(), "I'll give you " + cost_str( this_offer->amount ) + " for " + strip_colours( query_multiple_short( this_offer-> objects ) ) + ", what do you think?" ); return 1; } // Now they've given a response either stop or take their goods // and give them money. void do_yes( object person ) { object money, *selling, ob; mixed *m_array; string zone; if( !this_offer || person != this_offer->who ) return; whisper( person, "You've got a deal." ); selling = ({ }); foreach( ob in this_offer->objects ) { ob->add_property( "fenced", (string)person->query_name() ); selling += ({ ob }); } m_array = (mixed *)MONEY_HAND->create_money_array( this_offer->amount, calc_place() ); money = clone_object( MONEY_OBJECT ); money->set_money_array( m_array ); if( (int)money->move( person ) != MOVE_OK) { money->move( environment( this_object() ) ); whisper( person, "You're too heavily burdened to accept all " "that money, so I'll just put it on the floor." ); } else { tell_object( person, this_object()->a_short() + " slips you " + cost_str( this_offer->amount ) + ".\n" ); tell_room( environment(), this_object()->a_short() + " slips some coins " "to " + person->a_short() + ".\n", ({person}) ); } this_offer = 0; if( sizeof( move_data ) > 0 ) { foreach( zone in move_data ) { this_object()->add_move_zone( zone ); } this_object()->remove_move_zone( 0 ); move_data = ({ }); } } void do_no( object player ) { string zone; object customer, thing; int returned, burdened; if( !this_offer || player != this_offer->who ) return; whisper( player, "Ok, have it your own way then." ); customer = this_offer->who; burdened = 0; returned = 0; foreach( thing in this_offer->objects ) { if( !thing ) { whisper( customer, "Seems thare is a hole in my sack!" ); continue; } if( thing->move( customer ) != MOVE_OK ) { burdened = 1; thing->move( environment( this_object() ) ); whisper( customer, "I'll just put the " + thing->short() + " down here since you are too burdened to accept it." ); } else { returned = 1; } } if( burdened && returned ) { tell_object( customer, this_object()->a_short() + " returns the other items " "to you.\n" ); } else { if( returned ) tell_object( customer, this_object()->a_short() + " returns the items to " "you.\n" ); } tell_room( environment(), this_object()->a_short() + " returns the " "items to " + customer->a_short() + ".\n", ({ customer }) ); this_offer = 0; if( sizeof( move_data ) > 0 ) { foreach( zone in move_data ) { this_object()->add_move_zone( zone ); } this_object()->remove_move_zone( 0 ); move_data = ({ }); } } void whisper( object ob, string message ) { do_command( "whisper " + message + " to " + ob->query_name() ); } int busy() { if( this_offer ) return 1; return 0; } void event_exit( object ob, string message, object to ) { object customer, thing; int returned, burdened; if( this_offer && ob == this_offer->who ) { whisper( ob, "Since you're leaving, I'll give your stuff back." ); customer = this_offer->who; burdened = 0; returned = 0; foreach( thing in this_offer->objects ) { if( !thing ) { whisper( customer, "Seems thare is a hole in my sack!" ); continue; } if( thing->move( customer ) != MOVE_OK ) { burdened = 1; thing->move( environment( this_object() ) ); whisper( customer, "I'll just put the " + thing->short() + " down here since you are too burdened to accept it." ); } else { returned = 1; } } if( burdened && returned ) { tell_object( customer, this_object()->a_short() + " returns the other " "items to you.\n" ); } else { if( returned ) tell_object( customer, this_object()->a_short() + " returns the items " "to you.\n" ); } tell_room( environment(), this_object()->a_short() + " returns the " "items to " + customer->a_short() + ".\n", ({ customer }) ); this_offer = 0; } } int attack_by( object ob ) { int burdened, returned; object customer, thing; if( this_offer && this_offer->who && environment( this_offer->who ) == environment( this_object() ) && this_offer->offer_time > time() - 60 ) { do_command( "say Hey! I'm trying to do business here!" ); whisper( this_offer->who, "Hey, you'd better take these." ); customer = this_offer->who; burdened = 0; returned = 0; foreach( thing in this_offer->objects ) { if( !thing ) { whisper( customer, "Seems thare is a hole in my sack!" ); continue; } if( thing->move( customer ) != MOVE_OK ) { burdened = 1; thing->move( environment( this_object() ) ); whisper( customer, "I'll just put the " + thing->short() + " down here since you are too burdened to accept it." ); } else { returned = 1; } } if( burdened && returned ) { tell_object( customer, this_object()->a_short() + " returns the other " "items to you.\n" ); } else { if( returned ) tell_object( customer, this_object()->a_short() + " returns the items " "to you.\n" ); } tell_room( environment(), this_object()->a_short() + " returns the " "items to " + customer->a_short() + ".\n", ({ customer }) ); this_offer = 0; } return ::attack_by(ob); } /*void event_person_say( object thing, string start, string mess, string lang) { if ( !( thing->query_current_language() == "morporkian" ) ) { lang = "morporkian"; } ::event_person_say( thing, start, mess, lang ); }*/ // Called when time's up, being attacked, said no or is leaving. void give_back() { int burdened, returned; object customer, thing; customer = this_offer->who; burdened = 0; returned = 0; foreach( thing in this_offer->objects ) { if( !thing ) { whisper( customer, "Seems thare is a hole in my sack!" ); continue; } if( thing->move( customer ) != MOVE_OK ) { burdened = 1; thing->move( environment( this_object() ) ); whisper( customer, "I'll just put the " + thing->short() + " down here " "since you are too burdened to accept it." ); } else { returned = 1; } } if( burdened && returned ) { tell_object( customer, this_object()->a_short() + " returns the other items " "to you.\n" ); } else { if( returned ) tell_object( customer, this_object()->a_short() + " returns the items to " "you.\n" ); } tell_room( environment(), this_object()->a_short() + " returns the " "items to " + customer->a_short() + ".\n", ({ customer }) ); this_offer = 0; } string query_current_offer() { string str; str = "\nCustomer: " + ( this_offer->who )->short() + "\n"; str += "Amount: " + this_offer->amount + "\n"; str += "Offer time: " + this_offer->offer_time + "\n"; str += "Objects: " + query_multiple_short( this_offer->objects ); return str; }