/**
* This room will handle craft shop like things, where you sell stuff to
* the store and it will sell it onto other players after taking
* a margin. This can be used for potions, pottery, swords, anything!
* This has a few small hooks in here to handle categories in the
* sell process. Most of the category handling code is dealt with in
* the category based craft shop.
* @author Pinkfish
* @started Thu Feb 5 15:39:57 CST 1998
*/
#include <money.h>
#include <shops/craft_shop.h>
private nosave object _controller;
private nosave string _save_dir_name;
private nosave function _allowed_to_sell;
private nosave function _open_function;
private nosave function _when_sold_func;
private nosave int _max_sell_per_person;
private nosave int _cut;
private nosave int _minimum_cost;
private nosave function _extra_sell_check;
private nosave int _always_ask_price;
int do_sell(object *obs);
void set_controller(string name);
int do_buy(object *obs);
int do_delete(string id);
int do_browse(object *obs);
int do_change(object *obs, string str);
int do_change_name(object *obs, string str);
void set_allowed_to_sell(function f);
void set_minimum_cost(int i);
protected void sell_name(string name, object *sellable);
protected void sell_choice(string choice, object *sellable, string *names);
protected void determine_cost(string cost, string name, object *sellable);
protected void confirm_sale(string answer, int value, string name,
object *sellable, string category);
protected void confirm_sell_name_choice(string answer, string name,
object *sellable);
protected void complete_sale(int value, string name, object *sellable, string category);
protected void do_confirm_sale(int value, string name, object *sellable);
void set_cut(int value);
int query_cut();
int check_open(object player);
mixed query_property(string name);
string the_short();
void create() {
/* Always return true. */
if (!_allowed_to_sell) {
set_allowed_to_sell((: 1 :));
}
/* The default cut is 10% */
if (!_cut) {
set_cut(10);
}
/* Make it really 12 am pence. */
if (!_minimum_cost) {
set_minimum_cost(12 * 4);
}
if (!_controller && _save_dir_name) {
set_controller("/std/shops/controllers/craft_shop_controller");
_controller->load_it();
}
} /* create() */
/**
* This attempts to figure out how much the person is telling us the
* item costs.
* @param str the string to get the value of
*/
int value_from_string(string str, string place) {
return MONEY_HAND->value_from_string(str, place);
} /* value_from_string() */
/**
* This method handles the saving of the file to the disk.
* @param type the type of file to save
* @param value the value to save to it
* @param fname the file name is optional and only used for data files
*/
protected void do_save_file(int type, string value, string fname) {
string tmp;
switch (type) {
case CRAFT_SHOP_MAIN_SAVE_FILE :
tmp = save_variable(value);
if (file_size(_save_dir_name + ".o") != -1) {
unguarded( (: rename(_save_dir_name + ".o",
_save_dir_name + ".o.bak") :));
}
if (unguarded( (: write_file(_save_dir_name + ".o", $(tmp), 1) :) )) {
unguarded( (: rm(_save_dir_name + ".o.bak") :));
} else {
unguarded( (: rename(_save_dir_name + ".o.bak",
_save_dir_name + ".o") :));
}
break;
case CRAFT_SHOP_DATA_SAVE_FILE :
tmp = save_variable(value);
unguarded( (: write_file(_save_dir_name + "/" + $(fname),
$(tmp), 1) :));
break;
case CRAFT_SHOP_REMOVE_DATA_SAVE_FILE :
tmp = save_variable(value);
unguarded( (: rm(_save_dir_name + "/" + $(fname)) :));
break;
default :
printf("Unknown file type to write in %O, of %O\n", __FILE__, type);
break;
}
} /* do_save_file() */
/**
* This method handles the reading of the file to the disk.
* @param type the type of file to read
* @param fname the file name is optional and only used for data files
* @return the value read
*/
protected string do_read_file(int type, string fname) {
string tmp;
switch (type) {
case CRAFT_SHOP_MAIN_SAVE_FILE :
tmp = unguarded( (: read_file(_save_dir_name + ".o") :) );
if (tmp) {
return restore_variable(tmp);
}
return 0;
case CRAFT_SHOP_DATA_SAVE_FILE :
tmp = unguarded( (: read_file(_save_dir_name + "/" + $(fname)) :) );
if (tmp) {
return restore_variable(tmp);
}
return 0;
default :
printf("Unknown file type to read in %O, of %O\n", __FILE__, type);
break;
}
} /* do_read_file() */
/**
* This method sets the controller object for this shop.
* @param controller the controller name as a string
* @see query_controller()
*/
void set_controller(string name) {
if (_controller) {
_controller->dest_me();
}
_controller = clone_object(name);
_controller->set_save_function((: do_save_file($1, $2, $3) :));
_controller->set_load_function((: do_read_file($1, $2) :) );
} /* set_controller() */
/**
* This method returns the current value of the controller.
* @return the current controller
* @see set_controller()
*/
object query_controller() {
return _controller;
} /* query_controller() */
/**
* This method sets the save file associated with the controller. The save
* file should actually be a directory, the name of the directory plus a
* .o will be used for the save files. The directory must exist or weird
* errors will occur.
* This should always be set in the setup function of the room.
* @param fname the save file
* @see set_controller()
* @see query_save_dir()
*/
void set_save_dir(string fname) {
_save_dir_name = fname;
} /* set_save_dir() */
/**
* This method returns the file name of the save file.
* @return the file name of the save file
* @see set_save_dir()
*/
string query_save_dir() {
return _save_dir_name;
} /* query_save_dir() */
/**
* This method sets the function to use to check to see if the object
* is able to be sold here or not. The function will be called with
* one parameter, that is the object being check for buyability.
* @param func the function to check objects with
* @see query_allowed_to_sell()
*/
void set_allowed_to_sell(function func) {
_allowed_to_sell = func;
} /* set_allowed_to_sell() */
/**
* This method returns the function used to check to see if an object
* is able to be sold here or not.
* @return func the function to use for checking
* @see set_allowed_to_sell()
*/
function query_allowed_to_sell() {
return _allowed_to_sell;
} /* query_allowed_to_sell() */
/**
* This method sets the maxium allowed number of objects to be sold
* by each person into the shop.
* @param num the maximum number to be sold
* @see query_max_sell_per_person()
*/
void set_max_sell_per_person(int num) {
_max_sell_per_person = num;
} /* set_max_sell_per_person() */
/**
* This methods returns the maximum number of allowed objects to be
* sold by each person into the shop.
* @return the maximum number to be sold
* @see set_max_sell_per_person()
*/
int query_max_sell_per_person() {
return _max_sell_per_person;
} /* query_max_sell_per_person() */
/**
* This method sets the flag which makes the shop always ask for a price
* when it attempts to save something.
* @param ask_price the flag
*/
void set_always_ask_price(int ask_price) {
_always_ask_price = ask_price;
} /* set_always_ask_price() */
/**
* This method returns the flag on this object that tells us if the shop
* will always ask for a price
* @return the flag
*/
int query_always_ask_price() {
return _always_ask_price;
} /* query_always_ask_price() */
/**
* This method will return the maximum price this item is allowed to
* be sold for. This will return 0 if there is no maximum price
* @return 0 if there is no maximum price, or maximum price
*/
int query_maximum_sale_value(string person, object *obs) {
return 0;
} /* query_maximum_sale_value() */
/**
* This method returns any extra information about prices that the
* shop wants to display before entering a cost. This can be
* overridden in higher inherits to control this more effectively.
* @return an extra string to print
*/
string query_extra_price_information(string person, object *obs) {
return "";
} /* query_extra_price_information() */
/**
* @ignore yes
* Sets this room as a shop, to interface with the shoplift command.
* @return always returns 1
*/
int query_shop() {
return 1;
} /* query_shop() */
/**
* @ignore yes
* This method returns the list of things that can be shoplifted from this
* shop based on the input list.
*/
object *query_shop_lift_items(string str, object player) {
object *stuff;
object *pk_ok;
object ob;
stuff = match_objects_for_existence(str, ({ _controller->query_sell_list() }));
pk_ok = ({ });
foreach (ob in stuff) {
if (!pk_check(_controller->query_owner_of_shop_object(ob),
player, 1)) {
pk_ok += ({ ob });
}
}
if (sizeof(pk_ok) != sizeof(stuff)) {
player->add_failed_mess(previous_object(),
"You cannot shoplift $I since you cannot "
"shoplift from non-player killers.\n", stuff);
}
return pk_ok;
} /* query_shop_lift_items() */
/**
* This method is called when something is bought and tells us how much
* has been spent.
* @param value of the the items sold
* @param obs the objects bought
* @param player who bought them
* @param sellers the people whose items were bought
* @param names the names of the items bought
* @param cats the categories of the items bought
* @param values the values of each item
*/
void inform_of_buy(int value, object *obs, object player, string *sellers,
string *names, string *cats, int *values) {
} /* inform_of_buy() */
/**
* @ignore yes
* This place is always marked as 'no steal' for now.
*/
int query_no_steal() {
return 1;
} /* query_no_steal() */
/**
* This allows the system to override this for player run shops so the
* owner can discount peoples items.
* @param ob the object to test
* @return 1 if they can modify the item, 0 if not
*/
int is_able_to_change(object ob) {
return _controller->query_owner_of_shop_object(ob) ==
this_player()->query_name();
} /* is_able_change_ob() */
/**
* This method checks to see if this item is allowed to be sold in this shop.
* It assumes it is called from a add_command() method and sets up fail
* messages accordingly.
* @param obs the objects to check
* @param name the name of the person doing the selling
* @param sellable_names the names of the items to sell
*/
int is_allowed_to_sell(object* obs, string name, string *sellable_names) {
if ((sizeof(sellable_names)+sizeof(obs)) > query_max_sell_per_person() &&
query_max_sell_per_person()) {
add_failed_mess("Cannot sell $I, since you already have " +
query_num(sizeof(sellable_names)) +
" items listed.\n", obs);
return 0;
}
return 1;
} /* is_allowed_to_sell() */
/** @ignore yes */
void init() {
string storeroom;
storeroom = file_name(_controller->query_sell_list());
add_command("sell", "<indirect:object:me>");
add_command("list", "");
add_command("buy", "<indirect:object:" + storeroom + ">",
(: do_buy($1) :));
add_command("browse", "<indirect:object:" + storeroom + ">",
(: do_browse($1) :));
add_command("change", "price of <indirect:object:" + storeroom +
"> to <string>", (: do_change($1, $4[1]) :));
add_command("change", "name of <indirect:object:" + storeroom +
"> to <string>", (: do_change_name($1, $4[1]) :));
add_command("collect", "royalties");
add_command("delete", "<string'sell id'>",
(: do_delete($4[0]) :));
} /* init() */
/**
* This method sells an object into the craft shop.
* @param obs the objects to sell
* @return 1 on success, 0 on failure
* @see do_list()
* @see do_buy()
*/
int do_sell(object *obs) {
object *sellable;
string name;
string *sellable_names;
int i;
int cost;
string place;
// Check to make sure the shop is open.
if (!check_open(this_player())) {
return 0;
}
sellable = filter(obs, query_allowed_to_sell());
if (!sizeof(sellable)) {
add_failed_mess("This shop does not deal in $I.\n", obs);
return 0;
}
if (query_cut() != 100) {
write("Selling an item to this shop does not automatically give you the "
"money. You will get a cut of " + (100 - query_cut()) +
"% of the sale price once the item has been sold by the shop.\n");
}
name = this_player()->query_name();
if (!is_allowed_to_sell(sellable, name, sellable_names)) {
return 0;
}
sellable_names = _controller->query_owner_sellables(name);
sellable_names = uniq_array(sellable_names);
if (!sizeof(sellable_names)) {
write("You are not currently selling any items. What name "
"would you like to list " + query_multiple_short(sellable) +
" under? (Blank line to quit)\nList name: ");
input_to((: sell_name :), 0, sellable);
} else {
place = query_property("place");
if (!place) {
place = "default";
}
write("You currently have the following listed for sale:\n");
for (i = 0; i < sizeof(sellable_names); i++) {
cost = _controller->query_list_object_cost(sellable_names[i],
this_player()->query_name());
write(sprintf(" %c) %s (%s)\n", 'a' + i, sellable_names[i],
MONEY_HAND->money_value_string(cost, place)));
}
write("Select the letter of the choice to add to the item, or type "
"'create' to create a new listing name.\n"
"Your choice ([a-" + sprintf("%c", 'a' + sizeof(sellable_names) -1) +
"],create) ? ");
input_to((: sell_choice :), 0, sellable, sellable_names);
}
add_succeeded_mess(({ "", "$N starts to sell $I to the shop.\n" }),
sellable);
return 1;
} /* do_sell() */
/**
* This method makes sure a name is not too long and contains
* no colour codes.
* @param name the name to list the object as
* @return 0 if name is unacceptable, 1 if it's OK
*/
protected int check_sell_name( string name ) {
if (strlen(name) > CRAFT_SHOP_MAX_NAME_LENGTH) {
write("Sorry, that name is too long. It can be a maximum of " +
CRAFT_SHOP_MAX_NAME_LENGTH + " characters.\n");
return 0;
}
if (strsrch(name, "%^") != -1) {
write("Sorry, you cannot use colour sequences in names.\n");
return 0;
}
// Name was OK
return 1;
} // check_sell_name()
/**
* This method determines the name to list the object under. This is
* called when a new name is used.
* @param name the name to list the object as
* @param sellable the list of sellable objects
*/
protected void sell_name(string name, object *sellable) {
if (name == "" || name == 0) {
write("Ok, cancelling the sale of " + query_multiple_short(sellable) +
".\n");
return ;
}
if ( !check_sell_name( name ) ) {
input_to((: sell_name :), 0, sellable);
write("What name would you like to list " +
query_multiple_short(sellable) + " under? ");
return;
}
write("You wish to sell " + query_multiple_short(sellable) +
" as '" + name + "' (y/n)? ");
input_to((: confirm_sell_name_choice :), 0, name, sellable);
} /* sell_name() */
/**
* This method is used to confirm the choice of name to use when
* selling the object.
* @param answer the confirmation choice
* @param name the name to sell it as
* @param sellable the list of objects to sell
*/
protected void confirm_sell_name_choice(string answer, string name,
object *sellable) {
answer = lower_case(answer);
if (strlen(answer) > 0 && ( answer[0] == 'n' || answer[0] == 'q' ) ) {
write("Ok, cancelling the sale of " + query_multiple_short(sellable) +
".\n");
return ;
}
if (!strlen(answer) || answer[0] != 'y') {
write("Unknown selection.\n");
write("You wish to sell " + query_multiple_short(sellable) +
" as '" + name + "' (y/n)? ");
input_to( (: confirm_sell_name_choice :), 0, name, sellable);
return ;
}
write(query_extra_price_information(this_player()->query_name(), sellable));
write("How much money do you wish to list the item '" + name + "' for? ");
input_to((: determine_cost :), 0, name, sellable);
} /* confirm_sell_name_choice() */
/**
* This method is used when there is a list of object already listed. It
* will check to see if the choice entered is valid and then use that
* name when selling the object if it is.
* @param choice the selected choice
* @param sellable the array of sellable objects
* @param names the names of choices for name
*/
protected void sell_choice(string answer, object *sellables, string *names) {
int cost;
string place;
int pos;
if (answer == "" || (answer[0] == 'q' || answer[0] == 'Q')) {
write("Ok, cancelling the sale of " + query_multiple_short(sellables) +
".\n");
return ;
}
answer = lower_case(answer);
if (answer == "create") {
write("Please enter the name you wish to list " +
query_multiple_short(sellables) + " as.\nList name: ");
input_to((: sell_name :), 0, sellables);
return ;
}
if (strlen(answer) > 1 ||
(answer[0] < 'a' || answer[0] >= 'a' + sizeof(names))) {
write(sprintf("Your response must be between 'a' and '%c' or "
"'create'.\nChoice? ", 'a' + sizeof(names) - 1));
input_to((: sell_choice :), 0, sellables, names);
return ;
}
pos = answer[0] - 'a';
cost = _controller->query_list_object_cost(names[pos],
this_player()->query_name());
if (!cost || _always_ask_price) {
/* Hmm, the cost is not working, we need to set a cost as well. */
write("How much money do you wish to list the item '" + names[pos] +
"' for? ");
write(query_extra_price_information(this_player()->query_name(),
sellables));
input_to((: determine_cost :), 0, names[pos], sellables);
} else {
place = query_property("place");
if (!place) {
place = "default";
}
do_confirm_sale(cost, names[pos], sellables);
}
} /* sell_choice() */
/**
* This method figured out the cost of the item based on the value they
* type in.
* @param cost the cost of the item
* @param name the name of the item
* @param sellable the array of objects to sell
*/
protected void determine_cost(string cost, string name, object *sellable) {
int max;
int value;
string place;
place = query_property("place");
if (!place) {
place = "default";
}
value = value_from_string(cost, place);
if (value < _minimum_cost) {
if (!strlen(cost) ||
lower_case(cost)[0] == 'q') {
write("Quiting.\n");
return ;
}
write("You must list your item as costing more than " +
MONEY_HAND->money_value_string(_minimum_cost, place) + ".\n");
write(query_extra_price_information(this_player()->query_name(),
sellable));
write("What do you wish to list " + name + " for? ");
input_to("determine_cost", 0, name, sellable);
return ;
}
max = query_maximum_sale_value(this_player()->query_name(), sellable);
if (value > max && max) {
write("You must list your item as costing less than " +
MONEY_HAND->money_value_string(max, place) + ".\n");
write(query_extra_price_information(this_player()->query_name(),
sellable));
write("What do you wish to list " + name + " for? ");
input_to("determine_cost", 0, name, sellable);
return ;
}
do_confirm_sale(value, name, sellable);
} /* determine_cost() */
private void confirm_sale_question(int value,
string name,
object *sellables,
string category) {
string place;
place = query_property("place");
if (!place) {
place = "default";
}
write("Confirming your sale of " + query_multiple_short(sellables) +
" as '" + name +
"' " + (category?"in category " + category + " ":"") +
"for " + MONEY_HAND->money_value_string(value, place) + " (y/n)? ");
input_to((: confirm_sale :), 0, value, name, sellables, category);
} /* confirm_sale_question() */
/**
* This method will ask the person to confirm the sale. It will check
* the extra_sell_check function and then call the extra sale thing.
* @param value the value of the thing being sold
* @param name the name the thing is sold for
* @param sellables the things to sell
*/
protected void do_confirm_sale(int value, string name, object *sellables) {
if (_extra_sell_check) {
evaluate(_extra_sell_check,
(: confirm_sale_question :),
value, name, sellables);
} else {
confirm_sale_question(value, name, sellables, 0);
}
} /* do_confirm_sale() */
/**
* This method confirms the sale after the cost and name have been
* determined.
* @param answer the answer to confirm with
* @param value the value of the object
* @param name the name of the object
* @param sellable the list of sellable objects
* @param category the category of the object, 0 if none
*/
protected void confirm_sale(string answer, int value, string name,
object *sellable,
string category) {
if (answer == "" || answer[0] == 'q' || answer[0] == 'Q' ||
answer[0] == 'n' || answer[0] == 'N') {
write("Ok, aborting sale of " + query_multiple_short(sellable) + ".\n");
return 0;
}
if (answer[0] != 'y' && answer[0] != 'Y') {
write("Please answer yes or no.\n");
confirm_sale_question(value, name, sellable, category);
return 0;
}
complete_sale(value, name, sellable, category);
} /* confirm_sale() */
/**
* This method is called to complete the sale completely. It is split
* up into a second function to allow the extra sell stuff
* to work neatly.
* @param value the value of the objects to sell
* @param name the list name
* @param sellable the list of objects to sell
* @param category the category of the object, 0 if none
*/
protected void complete_sale(int value, string name, object *sellable,
string category) {
object *bought;
string place;
object ob;
/* First run them through the when sold function. */
if (_when_sold_func) {
foreach (ob in sellable) {
evaluate(_when_sold_func, ob);
}
}
bought = _controller->buy_objects(sellable, name, value,
this_player()->query_cap_name(), category);
place = query_property("place");
if (!place) {
place = "default";
}
if (sizeof(bought)) {
write("Sold " + query_multiple_short(bought) + ", listed as '" +
name + "' " + (category?" in category " + category + " ":"") +
"for " + MONEY_HAND->money_value_string(value, place) +
".\nYou will need to come back later to pick up your royalties "
"for the sale.\n");
say(this_player()->query_cap_name() + " sold " +
query_multiple_short(bought) + " to " + the_short() + ".\n");
} else {
write("Unable to sell " + query_multiple_short(sellable) + ".\n");
}
} /* confirm_sale() */
/**
* This method will list the current set of objects which are
* available to buy.
* @return 1 on success, 0 on failure
* @see do_sell()
* @see do_buy()
*/
int do_list() {
string place;
object *obs;
object ob;
mixed *stuff;
string ret;
// Check to make sure the shop is open.
if (!check_open(this_player())) {
return 0;
}
/* Do a list of the wombles... */
obs = _controller->query_sell_list_obs();
if (!sizeof(obs)) {
add_failed_mess("The shop is empty.\n", ({ }));
return 0;
}
place = query_property("place");
if (!place) {
place = "default";
}
stuff = unique_array(obs, (: $1->short() :) );
stuff = sort_array(stuff, (:
strcmp(_controller->query_id_of_shop_object($1[0]),
_controller->query_id_of_shop_object($2[0])) :) );
ret = "";
foreach (obs in stuff) {
ob = obs[0];
ret += "$I$9=$C$" + _controller->query_id_of_shop_object(ob) +
") $C$" + ob->short() + " for " +
MONEY_HAND->money_value_string(ob->query_value(), place) + "; " +
query_num(sizeof(obs)) + " left.\n";
}
write("$P$Shop list$P$" + ret);
add_succeeded_mess( ({ "", "$N browses through the inventory.\n" }) );
return 1;
} /* do_list() */
/**
* This method will attempt to buy an object from the shops inventory.
* @param str the string to match an object with
* @return 1 on success, 0 on failure
* @see do_sell()
* @see do_list()
*/
int do_buy(object *obs) {
int value;
string place;
int player_money;
object *bought;
string *sellers;
string *names;
string *cats;
int *values;
// Check to make sure the shop is open.
if (!check_open(this_player())) {
return 0;
}
place = query_property("place");
if (!place) {
place = "default";
}
player_money = this_player()->query_value_in(place);
value = _controller->value_of_objects(obs);
if (value > player_money) {
add_failed_mess("You cannot buy $I as "+
( sizeof( obs ) > 1 ? "they cost ":"it costs " )+
MONEY_HAND->money_value_string(value, place) +
" and you do not have that much money.\n", obs );
return 0;
}
sellers = map(obs, (: _controller->query_owner_of_shop_object($1) :));
names = map(obs, (: _controller->query_name_of_shop_object($1) :));
cats = map(obs, (: _controller->query_category_of_shop_object($1) :));
values = map(obs, (: $1->query_value() :));
bought = _controller->sell_objects(obs, place, this_player(),
query_cut());
if (!sizeof(bought)) {
if (sizeof(bought) > 1) {
add_failed_mess("Cannot move any of $I into your inventory, nothing "
"bought.\n", obs);
} else {
add_failed_mess("Cannot move $I into your inventory, nothing "
"bought.\n", obs);
}
return 0;
}
inform_of_buy(value, bought, this_player(), sellers, names, cats, values);
add_succeeded_mess(({ "You buy $I for " +
MONEY_HAND->money_value_string(value, place) + ".\n",
"$N buys $I.\n" }), bought);
return 1;
} /* do_buy() */
/**
* This method will delete a list entry without the owner getting paid.
* @param str the string to match an object with
* @return 1 on success, 0 on failure
*/
int do_delete(string id ) {
if( !lordp(this_player()) ) {
add_failed_mess( "This command is reserved for lords.\n", ({ }) );
return 0;
}
if( !id || id == "" ) {
add_failed_mess( "You have to choose a valid sell id.\n", ({ }) );
return 0;
}
_controller->delete_objects(id);
add_succeeded_mess( "$N $V some things.\n", ({ }) );
return 1;
} /* do_delete() */
/**
* This function browses through the current selected list of items.
* @param obs the items to browse through
*/
int do_browse(object *obs) {
object *real_obs;
object ob;
string mess;
string read;
// Check to make sure the shop is open.
if (!check_open(this_player())) {
return 0;
}
if (sizeof(obs) > 10) {
add_failed_mess("You cannot browse more than 10 things at once.\n");
return 0;
}
real_obs = _controller->create_all_real_objects(this_player(), obs);
mess = "$P$Browse$P$";
foreach (ob in real_obs) {
mess += ob->the_short() + ":\n" + ob->long();
read = ob->query_readable_message();
if (read) {
mess += "You read " +
replace(ob->query_read_short(this_player()), "$name$",
ob->a_short()) + ":\n" +
ob->query_readable_message();
}
}
real_obs->move("/room/rubbish");
add_succeeded_mess(({ mess, "$N browses $I.\n" }), obs);
return 1;
} /* do_browse() */
/**
* This function changes the list price of an object.
* @param obs the object to change the list price of
* @param change the value to change the list price to
*/
int do_change(object *obs, string change) {
object *frog;
int value;
string place;
// Check to make sure the shop is open.
if (!check_open(this_player())) {
return 0;
}
frog = filter(obs, (: $1->short() == $2->short() :), obs[0]);
if (sizeof(frog) != sizeof(obs)) {
add_failed_mess("You cannot change the value of more than one "
"type of object at once.\n", obs);
return 0;
}
if (!is_able_to_change(obs[0])) {
add_failed_mess("You do not own $I.\n", obs);
return 0;
}
place = query_property("place");
if (!place) {
place = "default";
}
value = value_from_string(change, place);
if (value < _minimum_cost) {
add_failed_mess("You cannot set $I to a value less than " +
MONEY_HAND->money_value_string(_minimum_cost, place) + ".\n",
obs);
return 0;
}
_controller->change_value_of_shop_object(obs[0], value);
add_succeeded_mess( ({ "You change the value of $I to " +
MONEY_HAND->money_value_string(value, place) + ".\n",
"$N changes the value of $I.\n" }), obs[0..0]);
return 1;
} /* do_change() */
/**
* This function changes the list name of an object.
* @param obs the object to change the list name of
* @param new_name the value to change the list name to
*/
int do_change_name(object *obs, string new_name) {
object *frog;
// Check to make sure the shop is open.
if (!check_open(this_player())) {
return 0;
}
frog = filter(obs, (: $1->short() == $2->short() :), obs[0]);
if (sizeof(frog) != sizeof(obs)) {
add_failed_mess("You cannot change the value of more than one "
"type of object at once.\n", obs);
return 0;
}
if (!is_able_to_change(obs[0])) {
add_failed_mess("You do not own $I.\n", obs);
return 0;
}
if( !check_sell_name( new_name ) ) {
add_failed_mess( "Try another name.\n", ({ }) );
return 0;
}
if (_controller->change_name_of_shop_object(obs[0], new_name)) {
add_succeeded_mess(({ "You change the name of $I to " +
new_name + ".\n",
"$N changes the name of $I.\n" }),
({ obs[0] }) );
} else {
add_failed_mess("The name " + new_name + " is already in use.\n", obs);
}
return 1;
} /* do_change_name() */
/**
* This method collects any royalties the current player is owed.
* @return 1 on succes, 0 on failure
*/
int do_collect() {
string name;
string place;
int value;
// Check to make sure the shop is open.
if (!check_open(this_player())) {
return 0;
}
name = this_player()->query_name();
value = _controller->query_royalty(name);
if (!value) {
add_failed_mess("You have no money owed to you here.\n");
return 0;
}
if (value < 0) {
add_failed_mess("You owe money to " + the_short() + ".\n");
return 0;
}
place = query_property("place");
if (!place) {
place = "default";
}
_controller->pay_out_royalty(name, place);
add_succeeded_mess(({ "You collect " +
MONEY_HAND->money_value_string(value, place) +
" in royalties.\n",
"$N collects some money in royalties.\n" }));
return 1;
} /* do_collect() */
/**
* This method sets the cut for the object.
* @param new_cut the new cut of the object
* @see query_cut()
*/
void set_cut(int new_cut) {
_cut = new_cut;
} /* set_cut() */
/**
* This method queries the current cut defined for this shop.
* @return the current cut for the shop
* @see set_cut()
*/
int query_cut() {
return _cut;
} /* query_cut() */
/**
* This method sets the minimum allowed cost for the item in the
* shop inventory.
* @param cost the minimum cost
* @see query_minimum_cost()
*/
void set_minimum_cost(int cost) {
_minimum_cost = cost;
} /* set_minimum_cost() */
/**
* This method returns the minimum allowed cost for an item in the
* shop inventory.
* @see set_minimum_cost()
*/
int query_minimum_cost() {
return _minimum_cost;
} /* query_minimum_cost() */
/**
* This method sets the function to be called on all the objects when
* they are sold. For instance this can be used to close all books
* etc.
* @param func the function to use
* @example
* // Close the book when it is sold.
* set_when_sold_function( (: $1->set_open_page(0) :) );
*/
void set_when_sold_function(function func) {
_when_sold_func = func;
} /* set_when_sold_function() */
/**
* This method returns the when sold function.
* @return the when sold function
* @see set_when_sold_function()
*/
function query_when_sold_function() {
return _when_sold_func;
} /* query_when_sold_function() */
/**
* This method sets the function to be called to check to see if the shop
* is open. If this is not set then the shop is always assumed to be
* open. The function returns a non-zero value then the shop is considered
* closed, if the function returns a value other than 1 then the default
* fail message will not be added.
* @param func the function to use for open tests
* @example
* // The shop is only open if gammer is alive.
* set_open_function( (: (gammer?1:0) :) );
* @see check_open()
* @example
* void setup() {
* ...
* // Setup the open function.
* set_open_function( (: do_open_check :) );
* } /\* setup() *\/
*
* int do_open_check(object player) {
* if (!gammer) {
* add_failed_mess("There appears to be no shopkeeper here!\n");
* return 2;
* }
* return 0;
* } /\* do_open_check() *\/
*/
void set_open_function(function func) {
_open_function = func;
} /* set_open_function() */
/**
* This method returns the function used to check to see if the shop is
* open or not.
* @return the shop open function
* @see set_open_function()
*/
function query_open_function() {
return _open_function;
} /* query_open_function() */
/**
* This method checks to see if the shop is open or not. It will setup the
* default fail message if this is what is needed.
* @param player
* @see set_open_function()
*/
int check_open(object player) {
int val;
val = evaluate(_open_function, player);
if (val == 1) {
add_failed_mess("The shop is not open.\n");
return 0;
}
return !val;
} /* check_open() */
/**
* This method sets the extra sell function for the shop. The extra sell
* function is called after the sell process is almost finished. It can
* check for extra things needed in the sell process, like which page of
* the book to browse.
* @param func the extra sell function
* @see query_extra_sell_check()
* @see complete_sell()
*/
void set_extra_sell_check(function func) {
_extra_sell_check = func;
} /* set_extra_sell_check() */
/**
* This method returns the extra sell check function.
* @return the extra sell check function
* @see set_extra_sell_check()
*/
function query_extra_sell_check() {
return _extra_sell_check;
} /* query_extra_sell_check() */
void dest_me() {
if(_controller) {
_controller->dest_me();
}
} /* dest_me() */