/* store.c Zilanthius sept 1992, update feb. 93 */ static status sell_armour, sell_weapon, sell_treasure; /* store.c updated for new economy by Angel Feb 1994 */ /* update by kingbilly, update zilanthius jan. 94 */ /* I converted some store code I made into a configurable type * This can be inherited in the same fashion as "room/room", except * you must use a prepended reset to clone in the shop owner. It would * also be advisable to mention in the long that there is a "list" to * "look at" for shop instructions. * * There is only one extra function to set, set_owner(name). * * If you wish to use your own monster add to your code the function, * set_owner() into your own file. inherit "inherit/store"; reset(arg){ ::reset(); if(arg) return; set_owner("farin"); etc..code as you would a normal room inherited from /room/room } */ #include <mudlib.h> inherit ROOM; /* shop configuration */ #define MAX_VALUE 1000 /* max. money when selling + charisma */ #define MONEY_MOD 6 /* was previously 2, now 3x what it was */ #define STORE_ROOM "/room/city/shop/store_room" #define NAME (string)this_player()->query_name() #ifdef PAGER #define MAX_LIST_LENGTH 50 #else #define MAX_LIST_LENGTH 30 /* item list length before truncate sign */ #endif /* PAGER */ #define MAX_STOCK 6 /* maximum stock of each specific item */ #define TOTAL_STOCK 60 /* total number of armour, weapon, treasure */ #define OWNER_STAT 15 #define BARGAIN (int)this_player()->query_charisma() +\ (int)this_player()->bargain_bonus() object STORE_ARMOUR; object STORE_WEAPON; object STORE_TREASURE; string owner; /* fn prototypes */ void set_owner(string arg); #ifdef PAGER varargs void inventory(object arg, string fn); #else void inventory(object arg); #endif mixed calc_value(int i); void reset(status arg) { if(owner && !present(lower_case(owner))) set_owner(owner); if(arg) return; #ifdef NATIVE_MODE } void create() { #endif /* native */ set_weather(2, 1, 1); } void init() { ::init(); /*** if you do forget to set_name() - defaults to "Farin" ***\ if(!owner) set_owner(0); /*** This is so you don't get a new holder everytime you update the shop ***/ if(!STORE_ARMOUR || !STORE_WEAPON || !STORE_TREASURE) { int i; string filename; object *inv; call_other(STORE_ROOM,"???"); /* load the storeroom */ inv = all_inventory(find_object(STORE_ROOM)); for(i = 0; i < sizeof(inv); i++) { if(inv[i]->id(file_name(this_object()))){ if(inv[i]->id("armour")) STORE_ARMOUR = inv[i]; if(inv[i]->id("weapon")) STORE_WEAPON = inv[i]; if(inv[i]->id("treasure")) STORE_TREASURE = inv[i]; } } } /*** Make the storage containers ***/ if(!STORE_ARMOUR){ STORE_ARMOUR = clone_object(CONTAINER); STORE_ARMOUR -> set_name("armour"); STORE_ARMOUR -> set_alt_name(file_name(this_object())); STORE_ARMOUR -> set_short("Armour: "+file_name(this_object())); STORE_ARMOUR -> set_weight(10000); STORE_ARMOUR -> set_max_weight(100000); #ifdef NATIVE_MODE STORE_ARMOUR->move(STORE_ROOM); #else move_object(STORE_ARMOUR, STORE_ROOM); #endif /* NATIVE_MODE */ } if(!STORE_WEAPON) { STORE_WEAPON = clone_object(CONTAINER); STORE_WEAPON -> set_name("weapon"); STORE_WEAPON -> set_alt_name(file_name(this_object())); STORE_WEAPON -> set_short("Weapon: "+file_name(this_object())); STORE_WEAPON -> set_weight(10000); STORE_WEAPON -> set_max_weight(100000); #ifdef NATIVE_MODE STORE_WEAPON->move(STORE_ROOM); #else move_object(STORE_WEAPON, STORE_ROOM); #endif /* NATIVE_MODE */ } if(!STORE_TREASURE){ STORE_TREASURE = clone_object(CONTAINER); STORE_TREASURE -> set_name("treasure"); STORE_TREASURE -> set_alt_name(file_name(this_object())); STORE_TREASURE -> set_short("Treasure: "+file_name(this_object())); STORE_TREASURE -> set_weight(10000); STORE_TREASURE -> set_max_weight(100000); #ifdef NATIVE_MODE STORE_TREASURE->move(STORE_ROOM); #else move_object(STORE_TREASURE, STORE_ROOM); #endif /* NATIVE_MODE */ } /*** Shop actions ***/ add_action("sell","sell"); add_action("list","list"); add_action("buy","buy"); add_action("buy","browse"); /* same find ob routine */ add_action("value","value"); add_action("look_at", "read"); add_action("storeroom","storeroom"); } status storeroom(){ if(this_player()->query_security_level()){ this_player()->move_player("storeroom#"+STORE_ROOM); return 1; } } void long(status wiz) { ::long(wiz); if(this_player()->query_security_level()){ write("You also notice the store room exit: <storeroom>\n"); } } status look_at(string str) { if(str == "list" || str == "sign"){ write(" -=[ Buy, Sell, and Value - Armours, Weapons, & Treasures ]=-\n\n"+ " Buy: buy <item>, buy <number> armour (or a),\n"+ " buy <number> weapon (or w), buy <number> treasure (or t).\n"+ " Sell: sell <all>, sell <item>.\n"+ " Value: value <item>.\n"+ " List: list, list <armour> (or a), list <weapon> (or a),\n"+ " list <treasure> (or t).\n"+ "Browse: browse <item>, browse <number>a, browse <number>w, "+ "browse <number>t.\n\n"); write("Conversion rate: 1 gold = 10 silver, 1 silver = 100 copper\n"); return 1; } return ::look_at(str); } status sell(string str){ int i, value; object *ob; status flag; if(!present(lower_case(owner), this_object())){ write(owner+" is not here right now, so you cannot sell anything.\n"); return 1; } if(!str){ write("Sell what?\n"); return 1; } if(str == "all"){ ob = all_inventory(this_player()); } else if(present(str, this_player())) { ob = ({ present(str, this_player()), }); } else { write(owner+" says: I'm not interested in a "+str+".\n"); return 1; } for(i = 0; i < sizeof(ob); i++) { if(ob[i]->short() && ob[i]->query_value() && !ob[i]->drop()) { if(!ob[i]) continue; if(!sell_armour && ob[i]->armour_class()) { write(owner+" says: I'm not interested in "+ob[i]->short()+"\n"+ "\tGo and see an armourer or something!\n"); continue; } if(!sell_weapon && ob[i]->weapon_class()) { write(owner+" exclaims: I'm not interested in "+ob[i]->short()+".\n"+ "\tGo and see a weaponsmith!\n"); continue; } value = (int)ob[i]->query_value(); if(value > MAX_VALUE) value = MAX_VALUE; /* Bargaining skill */ if(random(OWNER_STAT) > random(BARGAIN)) value -= random(value/3); else value += random(value/4); write(owner +" haggles with you over the price of "+ (string)ob[i]->short() +".\n"); write(owner +" gives you "+calc_value(value)+" coins for "+ (string)ob[i]->short()+".\n"); this_player()->add_money(value); this_player()->add_weight((int)ob[i]->query_weight() * (-1)); if(ob[i]->armour_class()) { if(sizeof(all_inventory(STORE_ARMOUR)) > TOTAL_STOCK) { ob[i]->set_sell_destruct(1); } } else if(ob[i]->weapon_class()) { if(sizeof(all_inventory(STORE_WEAPON)) > TOTAL_STOCK) { ob[i]->set_sell_destruct(1); } } else { if(sizeof(all_inventory(STORE_TREASURE)) > TOTAL_STOCK) { ob[i]->set_sell_destruct(1); } } if(ob[i]->query_sell_destruct()) { write(owner + " hides the valuable item away...\n"); destruct(ob[i]); } else { #ifdef NATIVE_MODE if(ob[i]->armour_class()) ob[i]->move(STORE_ARMOUR); else if(ob[i]->weapon_class()) ob[i]->move(STORE_WEAPON); else ob[i]->move(STORE_TREASURE); #else if(ob[i]->armour_class()) move_object(ob[i],STORE_ARMOUR); else if(ob[i]->weapon_class()) move_object(ob[i],STORE_WEAPON); else move_object(ob[i],STORE_TREASURE); #endif /* NATIVE_MODE */ } flag = 1; } } if(!flag) write(owner +" isn't interested.\n"); return 1; } status list(string str) { if(sell_armour) if(str == "armour" || str == "armours" || str == "a"){ inventory(STORE_ARMOUR); } else if(sell_weapon) if(str == "weapon" || str == "weapons" || str == "w"){ inventory(STORE_WEAPON); } else if(str == "treasure" || str == "treasures" || str == "t"){ inventory(STORE_TREASURE); } else{ /* list all */ #ifdef PAGER if(sell_armour) { write("list armour\n"); inventory(STORE_ARMOUR,"armour"); } #else list("a"); list("w") ; list("t"); #endif /* PAGER */ return 1; } #ifndef PAGER write("#=-=#=-=#=-=#=-=#=-=#=-=#=-=#=-=#=-=#=-=#=-=#=-=#=-=#=-=#=-\n"); #endif /* PAGER */ return 1; } status buy(string str){ object ob, *inv; int value, number, i, j, abort; string type, *item_check; string verb; verb = query_verb(); if(!present(lower_case(owner))){ write(owner +" is not here right now, so you cannot "+verb+" anything.\n"); return 1; } if(!str){ write(capitalize(verb) +" what?\n"); return 1; } ob = present(str,STORE_ARMOUR); if(!ob) ob = present(str,STORE_WEAPON); if(!ob) ob = present(str,STORE_TREASURE); if(!ob) { if(sscanf(str,"%d%s",number,type) || sscanf(str,"%d %s",number,type)) { if(type == "armour" || type == " a" || type == "arm" || type == " armor" || type == " armour" || type == "a" || type == " arm" || type == "armor") ob = STORE_ARMOUR; else if(type == "weapon" || type == " w" || type == "weap" || type == " weapon" || type == "w" || type == " weap") ob = STORE_WEAPON; else if(type == "treasure" || type == " t" || type == "treas" || type == " treasure" || type == "t" || type == " treas") ob = STORE_TREASURE; else{ write(owner+" says: But I don't have that in stock!\n"+ " Perhaps you should try ["+verb+" <number>(a|w|t)]\n"); return 1; } inv = all_inventory(ob); item_check = ({}); ob = 0; for(i = 0; i < sizeof(inv); i++) { string tmp; int val; val = (int)inv[i]->query_max_value(); /* armour value changes */ if(!val) val = (int)inv[i]->query_value(); tmp = (string)inv[i]->short() +"#"+ val; if(member_array(tmp, item_check) != -1) continue; if(++j == number) { ob = inv[i]; break; } item_check += ({ tmp, }); if(++abort > MAX_LIST_LENGTH) break; } if(!ob) { write(owner+" says: But I don't have that in stock!\n"+ " Perhaps you should try ["+ verb +" <number>(a|w|t)]\n"); return 1; } } else{ write(owner+" says: But I don't have a "+ str +" in stock!\n"); return 1; } } if(!sell_armour && ob->armour_class()) { write(owner+" says: Hey, I'm not an armourer. Go there instead.\n"); return 1; } else if(!sell_weapon && ob->weapon_class()) { write(owner+" says: I'm not a weaponsmith. Go there instead!\n"); return 1; } if(verb == "browse") { write(owner +" shows you the "+ (string)ob->short() +"...\n\n"); ob->long(); return 1; } value = (int)ob->query_value() * 2; if(random(OWNER_STAT) > random(BARGAIN)) value += random(value/3); else value -= random(value/4); write(owner+" haggles with you over the price of "+ob->short()+".\n"); if((int)this_player()->query_money() < value) { write(owner+" says: You seem to have a cash flow problem!\n"); return 1; } if(!call_other(this_player(),"add_weight",(int)ob->query_weight())){ write(owner+" says: You should gain a bit more muscle before you\n"+ " buy the"+(string)ob->short()+".\n"); return 1; } say(NAME+" bought a "+ (string)ob->short() +".\n"); write(owner +" takes "+ calc_value(value) +" coins for "+ (string)ob->short() +"\n"); #ifdef NATIVE_MODE ob->move(this_player()); #else move_object(ob,this_player()); #endif /* NATIVE_MODE */ this_player()->add_money(-value); return 1; } status value(string str){ object ob; int value; if(!present(lower_case(owner))){ write(owner +" is not here right now, "+ "so how can you get him to value anything.\n"); return 1; } if(!str){ write("Value what?\n"); return 1; } ob = present(str,this_player()); if(!ob){ write(owner+" says: You don't have a "+ str +" to value.\n"); return 1; } value = (int)ob->query_value(); if(!value) { write(owner+" looks at the "+ str +" carefully...\n"+ owner+" says: I'd wouldn't know what to give you for the "+str+"!\n"); } else write(owner +" says: I think that "+calc_value(value)+ " coins is a fair price, don't you?\n"); return 1; } #ifdef PAGER varargs void inventory(object obj, string pager_exit) { #else void inventory(object obj) { #endif /* PAGER */ object ob, *inv; int i, val, abort; string str; string list; int cost; string *item_list, *item_check; int *item_number; string sh; string tmp, tmp_val, tmp2; /*** Lets make sure the shop has at least one object ***/ #ifdef NATIVE_MODE if(!present("torch", STORE_TREASURE)){ clone_object("objects/torch")->move(STORE_TREASURE); } if(!present("list", STORE_TREASURE)) { clone_object("objects/party_list")->move(STORE_TREASURE); } if(!present("parchment", STORE_TREASURE)){ ob = clone_object(TREASURE); ob -> set_name("parchment"); ob -> set_short("A sheet of parchment"); ob -> set_long( "A fine sheet of parchment. Perhaps it could be used to scribe "+ "spells with?\n"); ob -> set_value(500); ob -> set_weight(1); ob->move(STORE_TREASURE); } if(!present("ore", STORE_TREASURE)) { ob = clone_object(TREASURE); ob -> set_name("ore"); ob -> set_short("A hunk of ore"); ob -> set_long( "It seems to be a fine ore of metal, capable of being refined \n"+ "into a fine piece of armour, or perhaps a weapon of some sort.\n"); ob -> set_value(random(500) + 250); ob -> set_weight(2); ob->move(STORE_TREASURE); } if(!present("bag", STORE_TREASURE)){ clone_object("/objects/bag")->move(STORE_TREASURE); } if(!present("shield", STORE_ARMOUR)){ ob = clone_object(ARMOUR); ob -> set_name("shield"); ob -> set_short("Shield"); ob -> set_long("A wooden shield.\n"); ob -> set_weight(3); ob -> set_value(150); ob -> set_ac(1); ob -> set_type("shield"); ob->move(STORE_ARMOUR); } if(!present("shortsword", STORE_WEAPON)){ ob = clone_object(WEAPON); ob -> set_name("shortsword"); ob -> set_alias("sword"); ob -> set_short("A shortsword"); ob -> set_long("A small short sword.\n"); ob -> set_weight(4); ob -> set_class(10); ob -> set_value(400); ob -> set_type("slash"); ob -> set_length(24); ob->move(STORE_WEAPON); } if(!present("knife", STORE_WEAPON)){ ob = clone_object(WEAPON); ob -> set_name("knife"); ob -> set_short("A Knife"); ob -> set_long("A small knife.\n"); ob -> set_weight(3); ob -> set_class(6); ob -> set_value(110); ob -> set_type("thrust"); ob -> set_length(12); ob -> move(STORE_WEAPON); } #else if(!present("torch", STORE_TREASURE)){ move_object(clone_object("objects/torch"),STORE_TREASURE); } if(!present("list", STORE_TREASURE)) { move_object(clone_object("objects/party_list"),STORE_TREASURE); } if(!present("parchment", STORE_TREASURE)){ ob = clone_object(TREASURE); ob -> set_name("parchment"); ob -> set_short("A sheet of parchment"); ob -> set_long( "A fine sheet of parchment. Perhaps it could be used to scribe "+ "spells with?\n"); ob -> set_value(500); ob -> set_weight(1); move_object(ob, STORE_TREASURE); } if(!present("ore", STORE_TREASURE)) { ob = clone_object(TREASURE); ob -> set_name("ore"); ob -> set_short("A hunk of ore"); ob -> set_long( "It seems to be a fine ore of metal, capable of being refined \n"+ "into a fine piece of armour, or perhaps a weapon of some sort.\n"); ob -> set_value(random(500) + 250); ob -> set_weight(2); move_object(ob, STORE_TREASURE); } if(!present("bag", STORE_TREASURE)){ move_object(clone_object("/objects/bag"),STORE_TREASURE); } if(!present("shield", STORE_ARMOUR)){ ob = clone_object(ARMOUR); ob -> set_name("shield"); ob -> set_short("Shield"); ob -> set_long("A wooden shield.\n"); ob -> set_weight(3); ob -> set_value(150); ob -> set_ac(1); ob -> set_type("shield"); move_object(ob, STORE_ARMOUR); } if(!present("shortsword", STORE_WEAPON)){ ob = clone_object(WEAPON); ob -> set_name("shortsword"); ob -> set_alias("sword"); ob -> set_short("A short sword"); ob -> set_long("A small short sword.\n"); ob -> set_weight(4); ob -> set_wc(10); ob -> set_value(1300); ob -> set_type("slash"); ob -> set_length(24); move_object(ob, STORE_WEAPON); } if(!present("knife", STORE_WEAPON)){ ob = clone_object(WEAPON); ob -> set_name("knife"); ob -> set_short("A Knife"); ob -> set_long("A small knife.\n"); ob -> set_weight(3); ob -> set_class(6); ob -> set_value(110); ob -> set_type("thrust"); ob -> set_length(12); move_object(ob, STORE_WEAPON); } #endif /* NATIVE_MODE */ if(!obj) return 0; inv = all_inventory(obj); if(!sizeof(inv)) { string obj_name; if(obj->id("treasure")) obj_name = "treasure"; if(obj->id("armour")) obj_name = "armour"; if(obj->id("weapon")) obj_name = "weapons"; if(obj_name){ write(owner+" says: I don't have any "+obj_name+" at the moment.\n"); } else{ write(owner+" says: I don't have anything in stock at the moment.\n"); } } else{ list = ""; if(obj->id("armour")) list = "\n\n -=[ Armour ]=-\n\n"; if(obj->id("weapon")) list = "\n\n -=[ Weapon ]=-\n\n"; if(obj->id("treasure")) list = "\n\n -=[ Treasure ]=-\n\n"; list += "--=[ Item ]=-----------------=[ R.R.P.]=-----=[ Stock ]=---\n"; item_list = ({}); item_check = ({}); item_number = ({}); for(i = 0; i < sizeof(inv); i++) { int j; sh = (string)inv[i]->short(); val = (int)inv[i]->query_max_value(); /* armour value changes */ if(!val) val = (int)inv[i]->query_value(); tmp = sh +"#"+ val; if((j = member_array(tmp, item_check)) != -1) { if(item_number[j] == MAX_STOCK) destruct(inv[i]); else item_number[j] += 1; continue; } str = (sizeof(item_list) < 9) ? " " : ""; str += " "+(sizeof(item_list)+1)+". "+ sh +" "; str = extract(str,0,30); cost = (int)inv[i]->query_value() * 6; tmp_val = calc_value(cost); sscanf(tmp_val,"%d %s %s",cost, tmp_val, tmp2); if(cost < 10) str += " "; if(cost < 100) str += " "; str += " "+ cost +" "+ tmp_val +" "; str = extract(str,0,49); item_check += ({ tmp, }); item_list += ({ str, }); item_number += ({ 1, }); if(++abort > MAX_LIST_LENGTH) break; } for(j = 0; j < sizeof(item_list); j++) { list += item_list[j] + item_number[j] +"\n"; } /* alternative - this won't bug out so much, but no stock numbers. list += implode(item_list,"\n") +"\n"; */ if(i != sizeof(inv)) list += " **** Truncated ***\n"; } #ifdef PAGER ob = clone_object(PAGER); ob->page(list,pager_exit); #else write(list); #endif return; } #ifdef PAGER /* If 'list all' is used, page next storage container */ void pager_quit(string fn) { switch(fn) { case "armour": write("list weapon\n"); inventory(STORE_WEAPON,"weapon"); break; case "weapon": write("list treasure\n"); inventory(STORE_TREASURE); break; } } #endif /* PAGER */ void set_owner(string owner_name){ object owner_ob; if(!stringp(owner_name)) owner_name = "farin"; if(!owner) owner = capitalize(owner_name); owner_ob = clone_object("inherit/monster"); owner_ob -> set_name(lower_case(owner)); owner_ob -> set_magic_resist(100); owner_ob -> set_no_kill_flag(1); owner_ob -> set_race("human"); owner_ob -> set_short(owner+", the shopkeeper"); owner_ob -> set_alias("shopkeeper"); owner_ob -> set_long(owner +" has always run this shop. He is\n"+ "known for his greediness, and will rip-off anybody given\n"+ "given the opportunity.\n"); owner_ob -> set_al(30); owner_ob -> set_gender(1); owner_ob -> set_level(15); owner_ob -> set_wc(20); owner_ob -> set_ac(18); owner_ob -> set_hp(7050); owner_ob -> load_chat(5,({ owner+" gives you a sly grin.\n", owner+" says: Would you like to buy something?\n", owner+" glances at your purse string.\n", })); owner_ob -> load_a_chat(25,({ owner+" says: Youu'll never steal my goods!\n", owner+" gives you a wack over the head with his money bag.\n", })); owner_ob -> add_money(1200 + random(800)); #ifdef NATIVE_MODE owner_ob->move(this_object()); #else move_object(owner_ob, this_object()); #endif /* NATIVE_MODE */ if(!present("gully dwarf")) { #ifdef NATIVE_MODE clone_object("inherit/dwarf")->move(this_object()); #else move_object(clone_object("inherit/dwarf"),this_object()); #endif /* NATIVE_MODE */ } } status set_sell_armour() { return sell_armour = 1; } status set_sell_weapon() { return sell_weapon = 1; } status set_sell_treasure(){ return sell_treasure = 1; } string calc_value(int i) { int amount; string tmp; amount = i; tmp = ""; if(i >= 1000) tmp +=(i/1000 +" gold "); while(i >= 1000) { i -= 1000; } if(i >= 100) tmp += (i/100 +" silver "); while(i >= 100) { i -= 100; } if(i) tmp += (i +" copper "); return tmp; } int query_no_fight() { return 1; }