/* pawn shop to allow people to get money for possessions and get them back
within a certain period of time. */
inherit "std/room";
#include "money_adjust.h"
#include "shop.h"
#include "money.h"
#include "move_failures.h"
void clean_up(int flag) { }
int clean_up_room(int flag) { return 1; }
#define VALUE query_value() * 2 / 5
#include "timestuff.h"
string *people;
object *objs;
int *times;
string store, shop;
int hold_time;
string *buy_mess, *sell_mess, list_mess, value_mess;
/* price adjustment variables and functions, Anirudh */
mapping market_data, race_prefs;
int last_changed_price,handled_since_last;
int do_weight_min(int amt, int weight, int material, int buysell);
int do_cha_adjust(int amt, int cha, int updown);
int do_race_adjust(int amt, string race, int updown);
int set_race_pref(string race, int race_perc);
void add_bought(object ob);
void add_sold(object ob);
void add_new_item(object ob,string str);
void check_adjust_prices();
void adjust_prices();
void reset_market();
int query_multiplier(object ob);
void create() {
market_data = ([ ]);
seteuid((string)"/secure/master"->creator_file(file_name(this_object())));
restore_object(file_name(this_object()));
people = ({ });
objs = ({ });
times = ({ });
store = "/room/pawnstore";
shop = "/room/storeroom";
hold_time = 1800;
set_short("Pawn Shop");
set_long(
"You are in a Pawn shop. You can value, leave and reclaim things here. "
"There is a sign describing how the shop works.\n");
set_light(60);
buy_mess = ({ "You reclaim $ob$ for $money$.\n",
"$client$ reclaims $ob$.\n" });
sell_mess = ({ "You leave $ob$ for $money$.\n",
"$client$ leaves $ob$.\n" });
list_mess = "$ob$\t\t$money$\n";
value_mess = "The $ob$ would get you $money$.\n";
::create();
}
void set_sell_message(mixed str) { sell_mess = str; }
void set_buy_message(mixed str) { buy_mess = str; }
void set_value_message(mixed str) { value_mess = str; }
void set_list_message(mixed str) { list_mess = str; }
mixed query_sell_mess() { return sell_mess; }
mixed query_list_mess() { return list_mess; }
mixed query_value_mess() { return value_mess; }
mixed query_buy_mess() { return buy_mess; }
void dest_me() {
int loop;
if(!people) people = ({ });
for(loop = 0; loop < sizeof(people); loop++) {
tell_object(find_living(people[loop]),
"A little person runs up to you and hands you a note, then vanishes again.\n"
"The note reads:\n"
"Pawnbroker has gone broke. " + objs[loop]->query_name() + " sold to shop.\n");
objs[loop]->move(shop);
}
::dest_me();
}
string pawn_parse(string str, object ob, object client, string money,
string extra) {
string s1,s2,s3,rest;
rest = "";
while(sscanf(str,"%s$%s$%s", s1, s2, s3) == 3)
switch (s2) {
case "ob" :
str = s1+ob->short()+s3;
break;
case "client" :
str = s1+client->query_name()+s3;
break;
case "extra" :
str = s1+extra+s3;
break;
case "money" :
str = s1+money+s3;
break;
default :
rest = s1+"$"+s2+"$";
str = s3;
break;
}
return rest+str;
}
void do_parse(mixed arr, object ob, object client, string money,
string extra) {
if (stringp(arr))
write(pawn_parse(arr, ob, client, money, extra));
else {
write(pawn_parse(arr[0], ob, client, money, extra));
say(pawn_parse(arr[1], ob, client, money, extra));
}
}
void init() {
::init();
add_action("read", "read");
add_action("value_item", "value");
add_action("leave_item", "leave");
add_action("reclaim_item", "reclaim");
add_action("list_items", "list");
}
int read(string str) {
if(str != "sign") {
notify_fail("The only thing here to read is a sign.\n");
return 0;
}
write("You can leave things here in exchange for cash. The value of the "
"item determines the amount of cash you can get for it. If you do "
"not return and claim your item within " +
(hold_time / 60) + " minutes, then it "
"will be sold to a shop to reclaim its worth.\n"
"You can leave <item>, reclaim <item>, list, and value <item> here.\n"
"Selling things here gets you less money than the shop, but "
"reclaiming the item does not cost as much as buying it back from the "
"shop would.\n");
return 1;
}
void set_storeroom(string str) {
store = str;
}
string query_storeroom() {
return store;
}
void set_shop(string str) {
shop = str;
}
string query_shop() {
return shop;
}
void set_hold_time(int time) {
hold_time = time;
}
int query_hold_time() {
return hold_time;
}
int set_race_pref(string race, int race_perc) {
int i;
if(!m_sizeof(race_prefs)) race_prefs = ([ ]);
if(race_perc != -1 && race_perc < 100) race_perc = 100;
if(race == "good") {
for(i=0;i<sizeof(GOOD_RACES);i++)
race_prefs[GOOD_RACES[i]] = race_perc;
return race_perc;
}
if(race == "neutral") {
for(i=0;i<sizeof(NEUTRAL_RACES);i++)
race_prefs[NEUTRAL_RACES[i]] = race_perc;
return race_perc;
}
if(race == "evil") {
for(i=0;i<sizeof(EVIL_RACES);i++)
race_prefs[EVIL_RACES[i]] = race_perc;
return race_perc;
}
race_prefs[race] = race_perc;
return race_perc;
}
int value_item(string str) {
object *ob;
int loop,real_val, mass, material;
if(!str) {
notify_fail("Value what?\n");
return 0;
}
ob = find_match(str, this_player());
if(!sizeof(ob)) {
notify_fail("You do not have a " + str + ".\n");
return 0;
}
for(loop = 0; loop < sizeof(ob); loop ++) {
real_val = "/std/shop"->scaled_value((int)ob[loop]->query_value())*4/5;
real_val=real_val*MONEY_TRACKER->query_adj_fact(SBFLAG)/1000;
real_val = real_val*query_multiplier(ob[loop])/1000;
real_val = do_weight_min(real_val,ob[loop]->query_weight(),
ob[loop]->query_material(),1);
real_val = do_cha_adjust(real_val,this_player()->query_cha(),1);
if((real_val = do_race_adjust(real_val,this_player()->
query_race(),1)) == -101) {
notify_fail("This shop refuses to deal with your "+
"race.\n");
return 0;
}
do_parse(value_mess, ob[loop], this_player(),
(string)MONEY_HAND->money_string((mixed *)MONEY_HAND->
create_money_array(real_val)), "");
}
return 1;
}
int leave_item(string str) {
object *ob;
mixed *ma;
string person;
int loop, money_to_give, the_time, pos, mass, material;
if(!str) {
notify_fail("Leave what?\n");
return 0;
}
ob = find_match(str, this_player());
if(!sizeof(ob)) {
notify_fail("You do not have a " + str + ".\n");
return 0;
}
person = (string)this_player()->query_name();
the_time = time();
for(loop = 0, money_to_give = 0; loop < sizeof(ob); loop++) {
int temp, loop2;
temp = (int)"/std/shop"->scaled_value((int)ob[loop]->
query_value()) * 4 / 5;
temp=temp*MONEY_TRACKER->query_adj_fact(SBFLAG)/1000;
temp = temp*query_multiplier(ob[loop])/1000;
temp = do_weight_min(temp,ob[loop]->query_weight(),
ob[loop]->query_material(),1);
temp = do_cha_adjust(temp,this_player()->query_cha(),1);
if((temp = do_race_adjust(temp,this_player()->query_race(),1))==
-101) { notify_fail("This shop refuses to deal with your "+
"race.\n");
temp = 0;
return 0;
}
if(temp > MAX_AMOUNT) {
temp = MAX_AMOUNT;
}
if (!this_player()->query_creator())
add_bought(ob[loop]);
money_to_give += temp;
people += ({ person });
objs += ({ ob[loop] });
times += ({ the_time });
ob[loop]->move(store);
say((string)this_player()->query_cap_name() + " leaves a " +
ob[loop]->query_name() + " here.\n");
call_out("end_hold", hold_time, ob[loop]);
}
ma = (mixed *)MONEY_HAND->create_money_array(money_to_give);
this_player()->adjust_money(ma);
write("The pawnbroker gives you " +
MONEY_HAND->money_string(ma) + ".\n");
return 1;
}
void end_hold(object ob) {
int pos;
if(!ob) {
return;
}
pos = member_array(ob, objs);
ob->move(shop);
if(pos == -1) {
return 0;
}
tell_object(find_living(people[pos]), "Time limit for " + ob->query_name() + " has expired.\n");
people = delete(people, pos, 1);
objs = delete(objs, pos, 1);
times = delete(times, pos, 1);
}
int reclaim_item(string str) {
object *ob;
int loop, money_to_give, mass, material;
if(!str) {
notify_fail("reclaim what?\n");
return 0;
}
ob = find_match(str, store);
if(!sizeof(ob)) {
notify_fail("There are no " + str + "'s here.\n");
return 0;
}
for(loop = 0; loop < sizeof(ob); loop++) {
int pos, amt, ob_amt;
pos = member_array(ob[loop], objs);
if(pos != -1) {
amt = (int)this_player()->query_value();
ob_amt = (int)"/std/shop"->scaled_value((int)ob[loop]->query_value());
ob_amt=ob_amt*MONEY_TRACKER->query_adj_fact(SSFLAG)/1000;
ob_amt = ob_amt*query_multiplier(ob[loop])/1000;
ob_amt = do_weight_min(ob_amt,ob[loop]->query_weight(),
ob[loop]->query_material(),0);
ob_amt = do_cha_adjust(ob_amt,this_player()->query_cha(),0);
if((ob_amt = do_race_adjust(ob_amt,this_player()->query_race(),0))==
-101) { notify_fail("This shop refuses to deal with your "+
"race.\n");
return 0;
}
if (ob_amt < 1) ob_amt = 1;
if (ob_amt < amt) {
if (!this_player()->query_creator())
add_sold(ob[loop]);
amt -= ob_amt;
money_to_give -= ob_amt;
do_parse(buy_mess, ob[loop], this_player(),
(string)MONEY_HAND->money_string((mixed *)MONEY_HAND->
create_money_array(ob_amt)),"");
if(ob[loop]->move(this_player()) != MOVE_OK) {
ob[loop]->move(this_object());
write("It is too heavy for you and he puts it down in front of you.\n");
}
objs = delete(objs, pos, 1);
people = delete(people, pos, 1);
times = delete(times, pos, 1);
}
else {
write("You cannot afford to reclaim "+
(string)objs[pos]->query_name()+".\n");
}
}
}
write("This is costing you " + money_to_give + "\n");
this_player()->pay_money(({ "brass", -money_to_give }) );
return 1;
}
int list_items() {
int loop, flag,real_val, mass, material;
string person;
person = (string)this_player()->query_name();
for(flag = loop = 0; loop < sizeof(objs); loop++) {
if(people[loop] == person) {
flag = 1;
real_val = (int)"/std/shop"->scaled_value((int)objs[loop]->
query_value());
real_val=real_val*MONEY_TRACKER->query_adj_fact(SSFLAG)/1000;
real_val = real_val*query_multiplier(objs[loop])/1000;
real_val = do_weight_min(real_val,objs[loop]->query_weight(),
objs[loop]->query_material(),0);
real_val = do_cha_adjust(real_val,this_player()->query_cha(),0);
if((real_val = do_race_adjust(real_val,this_player()->
query_race(),0))==-101) {
notify_fail("This shop refuses to deal with your "+
"race.\n");
return 0;
}
if (real_val < 1) real_val = 1;
do_parse(list_mess, objs[loop], this_player(),
(string)MONEY_HAND->money_string((mixed *)MONEY_HAND->
create_money_array(real_val)), "");
}
}
if(!flag) {
write("Nothing left here by you.\n");
}
return 1;
}
/* changing price functions, Anirudh */
int do_race_adjust(int amt, string race,int updown) {
int temp;
if(!m_sizeof(race_prefs)) race_prefs = ([ ]);
if(!race_prefs[race]) return amt;
if(race_prefs[race] == -1) return -101;
if(updown) {
temp = amt*100/race_prefs[race]+1;
if(temp > amt) return amt;
return temp;
}
else {
temp = amt*race_prefs[race]/100-1;
if(temp < amt) return amt;
return temp;
}
return amt;
}
int do_weight_min(int amt,int mass, int material, int buysell) {
if(buysell) {
if (material == 2 && amt < mass*4/5) amt = mass*4/5;
else if (material == 1 && amt < mass/5) amt = mass/5;
else if (material == 3 && amt < mass*4/35) amt = mass*4/35;
else if (amt < mass*2/25) amt = mass*2/25;
}
else {
if (material == 2 && amt < mass*6/5) amt=mass*6/5;
else if (material == 1 && amt < mass*3/10 ) amt=mass*3/10;
else if (material == 3 && amt < mass*6/35) amt=mass*6/35;
else if (amt < mass*3/25) amt = mass*3/25;
}
return amt;
}
int do_cha_adjust(int amt, int cha, int updown) {
int temp;
if(!cha) return amt;
if(cha > 19) cha = 19;
if(cha > AVG_CHA) {
temp = 10*(cha - AVG_CHA)*CHA_AD*5/(18-AVG_CHA)/4;
if(temp > 100 && cha > 11) temp = 100;
if(updown) {
temp = amt*(1000+temp)/1000-1;
if(temp < amt) return amt;
}
else {
temp = amt*1000/(1000+temp)+1;
if(temp > amt) return amt;
}
return temp;
}
if(cha < AVG_CHA) {
temp = 10*(AVG_CHA-cha)*CHA_AD*5/(AVG_CHA-3)/4;
if(updown) {
temp = amt*1000/(1000+temp)+1;
if(temp > amt) return amt;
}
else {
temp = amt*(1000+temp)/1000-1;
if(temp < amt) return amt;
}
return temp;
}
return amt;
}
int query_multiplier(object ob) {
int i;
string item_path;
if (!m_sizeof(market_data)) restore_object(file_name(this_object()),1);
item_path = explode(file_name(ob),"#")[0];
if (market_data[item_path])
return market_data[item_path][4];
else
return 1000;
}
/* note: this is the function when the SHOP buys something */
void add_bought(object ob) {
int i;
string item_path;
if(this_player()->query_creator() ||
strsrch(this_player()->query_name(),"test") != -1)
return;
if (!m_sizeof(market_data))
restore_object(file_name(this_object()),1);
item_path = explode(file_name(ob),"#")[0];
if (market_data[item_path])
market_data[item_path][1]++;
else {
add_new_item(ob,item_path);
if (market_data[item_path])
market_data[item_path][1]++;
}
handled_since_last++;
check_adjust_prices();
if (m_sizeof(market_data))
save_object(file_name(this_object()));
}
/* and this is when the SHOP sells something */
void add_sold(object ob) {
int i;
string item_path;
if(this_player()->query_creator() ||
strsrch(this_player()->query_name(),"test") != -1)
return;
if (!m_sizeof(market_data)) restore_object(file_name(this_object()),1);
item_path = explode(file_name(ob),"#")[0];
if (market_data[item_path])
market_data[item_path][2]++;
else {
add_new_item(ob,item_path);
if (market_data[item_path])
market_data[item_path][2]++;
}
handled_since_last++;
check_adjust_prices();
if (m_sizeof(market_data))
save_object(file_name(this_object()));
}
void add_new_item(object ob, string item_path) {
if (!market_data[item_path]) {
market_data[item_path] = ({ ob->query_value(),0,0,0,1000,0 });
}
}
void check_adjust_prices() {
int timelapsed = TIMEKEEPER->query_running_time()-
last_changed_price;
if (timelapsed <= 0 || last_changed_price == 0) {
reset_market();
}
else if ( handled_since_last > 300 || timelapsed > BASE_WEEK) {
adjust_prices();
}
}
void adjust_prices() {
string *item_paths,ite;
int i,changemult,timelapsed,devisor,goaldif;
if(!m_sizeof(market_data)) restore_object(file_name(this_object()),1);
timelapsed = TIMEKEEPER->query_running_time()-last_changed_price;
/* don't want to overflow maxint here (percent of a week here) */
if (timelapsed < 20000000) {
timelapsed = timelapsed*100/BASE_WEEK;
}
else timelapsed = timelapsed*10/BASE_WEEK*10;
item_paths = m_indices(market_data);
for (i=0;i<sizeof(item_paths);i++) {
ite = item_paths[i];
if (market_data[ite][5]) {
market_data[ite][5] = 0;
market_data[ite][1]=market_data[ite][2]=0;
continue;
}
/* going to deal in 100ths of items... */
goaldif=market_data[ite][2]-market_data[ite][1]+1;
goaldif*=100;
devisor = 2*market_data[ite][2]+market_data[ite][1];
if (!devisor) devisor = 10;
changemult = goaldif*goaldif/(100*devisor);
if (goaldif > 0) {
market_data[ite][4] = market_data[ite][4]*11/10;
if (market_data[ite][4] > 1000)
market_data[ite][4] = 1000;
}
if (goaldif < 0) {
if (changemult > 2000) changemult = 2000;
market_data[ite][4] = market_data[ite][4]*
1000/(1000+changemult);
if (market_data[ite][4]<10) market_data[ite][4]=10;
}
market_data[ite][1]=market_data[ite][2]=0;
if (market_data[ite][4] == 1000)
market_data = m_delete(market_data,ite);
}
last_changed_price = (int) TIMEKEEPER->query_running_time();
handled_since_last = 0;
if (m_sizeof(market_data))
save_object(file_name(this_object()));
}
mapping query_market_data() {
return market_data;
}
void reset_market() {
string *item_paths,ite;
int i;
if (!m_sizeof(market_data)) restore_object(file_name(this_object()),1);
item_paths = m_indices(market_data);
for (i=0;i<sizeof(item_paths);i++) {
ite = item_paths[i];
market_data[ite][5] = market_data[ite][1]=
market_data[ite][2]=0;
}
last_changed_price = TIMEKEEPER->query_running_time();
handled_since_last = 0;
if (m_sizeof(market_data)) save_object(file_name(this_object()));
}
int set_md_value(string which_item,int which_one,int new_value) {
if (!m_sizeof(market_data)) restore_object(file_name(this_object()),1);
if(market_data[which_item]) {
market_data[which_item][which_one] = new_value;
}
if (m_sizeof(market_data)) save_object(file_name(this_object()));
if(market_data[which_item])
return market_data[which_item][which_one];
else return -101;
}