/**************************************************************************** * [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame | * * -----------------------------------------------------------| \\._.// * * SmaugWiz (C) 1998 by Russ Pillsbury (Windows NT version) | (0...0) * * -----------------------------------------------------------| ).:.( * * SMAUG (C) 1994, 1995, 1996 by Derek Snider | {o o} * * -----------------------------------------------------------| / ' ' \ * * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus, |~'~.VxvxV.~'~* * Scryn, Swordbearer, Rennard, Tricops, and Gorog. | * * ------------------------------------------------------------------------ * * Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael * * Chastain, Michael Quan, and Mitchell Tse. * * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik Staerfeldt, Tom Madsen, and Katja Nyboe. * * ------------------------------------------------------------------------ * * Shop and repair shop module * ****************************************************************************/ #include "stdafx.h" #include "smaug.h" #include "area.h" #include "mobiles.h" #include "objects.h" #include "rooms.h" #include "descriptor.h" #include "character.h" // Local function prototypes CCharacter *find_keeper (CCharacter* ch); CCharacter *find_fixer (CCharacter* ch); int get_cost (CCharacter* ch, CCharacter* keeper, CObjData* obj, BOOL fBuy); int get_repaircost (CCharacter* keeper, CObjData* obj); BOOL CanTrade (CCharacter* ch, CCharacter* keeper); // Shopping commands. CCharacter *find_keeper (CCharacter* ch) { CShopData *pShop = NULL; CCharacter *keeper = ch->GetInRoom ()->first_person; for ( ; keeper; keeper = keeper->GetNextInRoom ()) if (keeper->IsNpc () && (pShop = keeper->GetMobIndex ()->pShop)) break; if (! pShop) { ch->SendText ("You can't do that here.\n\r"); return NULL; } return keeper; } BOOL CanTrade (CCharacter* ch, CCharacter* keeper) { char buf [MAX_STRING_LENGTH]; CShopData *pShop = keeper->GetMobIndex ()->pShop; // Undesirables. if (! ch->IsNpc () && ch->IsKiller ()) { do_say (keeper, "Killers are not welcome!"); sprintf (buf, "%s the KILLER is over here!\n\r", ch->GetName ()); do_shout (keeper, buf); return FALSE; } if (! ch->IsNpc () && ch->IsThief ()) { do_say (keeper, "Thieves are not welcome!"); sprintf (buf, "%s the THIEF is over here!\n\r", ch->GetName ()); do_shout (keeper, buf); return FALSE; } // Shop hours. if (time_info.hour < pShop->open_hour) { do_say (keeper, "Sorry, come back later."); return FALSE; } if (time_info.hour > pShop->close_hour) { do_say (keeper, "Sorry, come back tomorrow."); return FALSE; } // Invisible or hidden people. if (! can_see (keeper, ch)) { do_say (keeper, "I don't trade with folks I can't see."); return FALSE; } if (! knows_language (keeper, ch->GetSpeaking (), ch)) { do_say (keeper, "I can't understand you."); return FALSE; } return TRUE; } /* * repair commands. */ CCharacter *find_fixer (CCharacter *ch) { char buf[MAX_STRING_LENGTH]; CCharacter *keeper; CRepairShopData *rShop; rShop = NULL; for (keeper = ch->GetInRoom ()->first_person; keeper; keeper = keeper->GetNextInRoom ()) if (keeper->IsNpc () && (rShop = keeper->GetMobIndex ()->rShop) != NULL) break; if (!rShop) { ch->SendText ("You can't do that here.\n\r"); return NULL; } /* * Undesirables. */ if (!ch->IsNpc () && ch->IsKiller ()) { do_say (keeper, "Killers are not welcome!"); sprintf (buf, "%s the KILLER is over here!\n\r", ch->GetName ()); do_shout (keeper, buf); return NULL; } if (!ch->IsNpc () && ch->IsThief ()) { do_say (keeper, "Thieves are not welcome!"); sprintf (buf, "%s the THIEF is over here!\n\r", ch->GetName ()); do_shout (keeper, buf); return NULL; } /* * Shop hours. */ if (time_info.hour < rShop->open_hour) { do_say (keeper, "Sorry, come back later."); return NULL; } if (time_info.hour > rShop->close_hour) { do_say (keeper, "Sorry, come back tomorrow."); return NULL; } /* * Invisible or hidden people. */ if (!can_see (keeper, ch)) { do_say (keeper, "I don't trade with folks I can't see."); return NULL; } if (!knows_language (keeper, ch->GetSpeaking (), ch)) { do_say (keeper, "I can't understand you."); return NULL; } return keeper; } int get_cost (CCharacter *ch, CCharacter *keeper, CObjData *obj, BOOL fBuy) { CShopData *pShop; int cost; BOOL richcustomer; int profitmod; if (!obj || (pShop = keeper->GetMobIndex ()->pShop) == NULL) return 0; if (ch->GetGold () > (ch->GetLevel () * ch->GetLevel () * 100000)) richcustomer = TRUE; else richcustomer = FALSE; if (fBuy) { // this line does nothing, and cost is unitialised! (Rustry) // cost = (int) (cost * (80 + UMIN (ch->GetLevel (), LEVEL_AVATAR))) / 100; profitmod = 13 - get_curr_cha (ch) + (richcustomer ? 15 : 0) + ((URANGE (5,ch->GetLevel (),LEVEL_AVATAR)-20)/2); cost = (int) (obj->cost * UMAX ((pShop->profit_sell+1), pShop->profit_buy+profitmod)) / 100; } else { CObjData *obj2; int itype; profitmod = get_curr_cha (ch) - 13 - (richcustomer ? 15 : 0); cost = 0; for (itype = 0; itype < MAX_TRADE; itype++) { if (obj->item_type == pShop->buy_type [itype]) { cost = (int) (obj->cost * UMIN ((pShop->profit_buy-1), pShop->profit_sell + profitmod)) / 100; break; } } POSITION pos = keeper->GetHeadCarryPos (); while (obj2 = keeper->GetNextCarrying (pos)) { if (obj->GetIndex () == obj2->GetIndex ()) { cost = 0; break; } } } if (obj->item_type == ITEM_STAFF || obj->item_type == ITEM_WAND) cost = (int) (cost * obj->value[2] / obj->value[1]); return cost; } int get_repaircost (CCharacter *keeper, CObjData *obj) { CRepairShopData *rShop; int cost; int itype; BOOL found; if (!obj || (rShop = keeper->GetMobIndex ()->rShop) == NULL) return 0; cost = 0; found = FALSE; for (itype = 0; itype < MAX_FIX; itype++) { if (obj->item_type == rShop->fix_type[itype]) { cost = (int) (obj->cost * rShop->profit_fix / 1000); found = TRUE; break; } } if (!found) cost = -1; if (cost == 0) cost = 1; if (found && cost > 0) { switch (obj->item_type) { case ITEM_ARMOR: if (obj->value[0] >= obj->value[1]) cost = -2; else cost *= (obj->value[1] - obj->value[0]); break; case ITEM_WEAPON: if (INIT_WEAPON_CONDITION == obj->value[0]) cost = -2; else cost *= (INIT_WEAPON_CONDITION - obj->value[0]); break; case ITEM_WAND: case ITEM_STAFF: if (obj->value[2] >= obj->value[1]) cost = -2; else cost *= (obj->value[1] - obj->value[2]); } } return cost; } void do_buy (CCharacter *ch, char *argument) { char arg [MAX_INPUT_LENGTH]; int maxgold; argument = one_argument (argument, arg); if (arg [0] == '\0') { ch->SendText ("Buy what?\n\r"); return; } if (ch->GetInRoom ()->IsPetShop ()) { char buf [MAX_STRING_LENGTH]; CCharacter *pet; CRoomIndexData *pRoomIndexNext; CRoomIndexData *in_room; if (ch->IsNpc ()) return; pRoomIndexNext = RoomTable.GetRoom (ch->GetInRoom ()->vnum + 1); if (! pRoomIndexNext) { bug ("Do_buy: bad pet shop at vnum %d.", ch->GetInRoom ()->vnum); ch->SendText ("Sorry, you can't buy that here.\n\r"); return; } in_room = ch->GetInRoom (); ch->SetInRoom (pRoomIndexNext); pet = get_char_room (ch, arg); ch->SetInRoom (in_room); if (pet == NULL || ! pet->IsNpc () || ! pet->IsPet ()) { ch->SendText ("Sorry, you can't buy that here.\n\r"); return; } if (ch->HasPet ()) { ch->SendText ("You already have a pet.\r\n"); if (ch->GetPet ()->GetInRoom () != in_room) ch->SendText ( "Your pet is lost. You had better go find it.\r\n"); return; } if (ch->GetGold () < 10 * pet->GetLevel () * pet->GetLevel ()) { ch->SendText ("You can't afford it.\n\r"); return; } if (ch->GetLevel () < pet->GetLevel ()) { ch->SendText ("You're not ready for this pet.\n\r"); return; } maxgold = 10 * pet->GetLevel () * pet->GetLevel (); ch->AddGold (-maxgold); ch->GetInRoom ()->GetArea ()->BoostEconomy (maxgold); pet = create_mobile (pet->GetMobIndex ()); ch->SetBoughtPet (); pet->SetPetFlag (); pet->SetCharmed (); argument = one_argument (argument, arg); if (arg [0] != '\0') { sprintf (buf, "%s %s", pet->GetName (), arg); pet->SetName (buf); } sprintf (buf, "%sA neck tag says 'I belong to %s'.\n\r", pet->GetDescription (), ch->GetName ()); pet->SetDescription (buf); pet->SendToRoom (ch->GetInRoom ()); add_follower (pet, ch); ch->SendText ("Enjoy your pet.\n\r"); act (AT_ACTION, "$n bought $N as a pet.", ch, NULL, pet, TO_ROOM); return; } else { CObjData *obj; int cost; int noi = 1; // Number of items short mnoi = 20; // Max number of items to be bought at once CCharacter *keeper = find_keeper (ch); if (! keeper || ! CanTrade (ch, keeper)) return; maxgold = keeper->GetLevel () * keeper->GetLevel () * 50000; if (is_number (arg)) { noi = atoi (arg); argument = one_argument (argument, arg); if (noi > mnoi) { act (AT_TELL, "$n tells you 'I don't sell that many items at" " once.'", keeper, NULL, ch, TO_VICT); ch->SetReplier (keeper); return; } } obj = get_obj_carry (keeper, arg); cost = (get_cost (ch, keeper, obj, TRUE) * noi); if (cost <= 0 || ! can_see_obj (ch, *obj)) { act (AT_TELL, "$n tells you 'I don't sell that -- try 'list'.'", keeper, NULL, ch, TO_VICT); ch->SetReplier (keeper); return; } if (! obj->IsInventory () && (noi > 1)) { interpret (keeper, "laugh"); act (AT_TELL, "$n tells you 'I don't have enough of those in " "stock to sell more than one at a time.'", keeper, NULL, ch, TO_VICT); ch->SetReplier (keeper); return; } if (ch->GetGold () < cost) { act (AT_TELL, "$n tells you 'You can't afford to buy $p.'", keeper, obj, ch, TO_VICT); ch->SetReplier (keeper); return; } if (obj->level > ch->GetLevel ()) { act (AT_TELL, "$n tells you 'You can't use $p yet.'", keeper, obj, ch, TO_VICT); ch->SetReplier (keeper); return; } if (obj->IsPrototype () && ch->GetTrustLevel () < LEVEL_IMMORTAL) { act (AT_TELL, "$n tells you 'This is a only a prototype! " "I can't sell you that...'", keeper, NULL, ch, TO_VICT); ch->SetReplier (keeper); return; } if (ch->carry_number + get_obj_number (obj) > ch->GetMaxItems ()) { ch->SendText ("You can't carry that many items.\n\r"); return; } if (ch->GetCarryWeight () + (get_obj_weight (obj) * noi) + (noi > 1 ? 2 : 0) > can_carry_w (ch)) { ch->SendText ("You can't carry that much weight.\n\r"); return; } if (noi == 1) { act (AT_ACTION, "$n buys $p.", ch, obj, NULL, TO_ROOM); act (AT_ACTION, "You buy $p.", ch, obj, NULL, TO_CHAR); } else { CString Descr = obj->GetShortDescr (); BOOL bPlural = Descr.GetAt (Descr.GetLength () - 1) == 's'; sprintf (arg, "$n buys %d $p%s.", noi, bPlural ? "" : "s"); act (AT_ACTION, arg, ch, obj, NULL, TO_ROOM); sprintf (arg, "You buy %d $p%s.", noi, bPlural ? "" : "s"); act (AT_ACTION, arg, ch, obj, NULL, TO_CHAR); act (AT_ACTION, "$N puts them into a bag and hands it to you.", ch, NULL, keeper, TO_CHAR); } ch->AddGold (-cost); keeper->AddGold (cost); if (keeper->GetGold () > maxgold) { keeper->GetInRoom ()->GetArea ()->BoostEconomy ( keeper->GetGold () - maxgold/2); keeper->SetGold (maxgold/2); act (AT_ACTION, "$n puts some gold into a large safe.", keeper, NULL, NULL, TO_ROOM); } if (obj->IsInventory ()) { CObjData *buy_obj, *bag; buy_obj = create_object (obj->GetIndex (), obj->level); // Due to grouped objects and carry limitations in SMAUG // The shopkeeper gives you a bag with multiple-buy, // and also, only one object needs be created with a count // set to the number bought. -Thoric if (noi > 1) { bag=create_object (OIdxTable.GetObj (OBJ_VNUM_SHOPPING_BAG),1); // perfect size bag ;) bag->value [0] = bag->weight + (buy_obj->weight * noi); buy_obj->count = noi; obj->GetIndex ()->count += (noi - 1); obj_to_obj (buy_obj, bag); obj_to_char (bag, ch); } else obj_to_char (buy_obj, ch); } else { obj_from_char (obj); obj_to_char (obj, ch); } return; } } // This is a new list function which allows level limits to follow as // arguments. This code relies heavily on the items held by the shopkeeper // being sorted in descending order by level. obj_to_char in handler.c was // modified to achieve this. Anyways, this list command will now throw flags // at the levels passed as arguments. This helps pick out equipment which is // usable by the char, etc. This was done rather than just producing a list // of equip at desired level because there would be an inconsistency between // #.item on one list and #.item on the other. // Syntax: // list - list the items for sale, should be sorted by // level // list # - list items and throw a flag at # // list #1 #2 - list items and throw flags at #1 and #2 // Note that this won't work in pets stores. Since you can't control // the order in which the pets repop you can't guarantee a sorted list. // Last Modified: May 25, 1997 -- Fireblade void do_list (CCharacter* ch, char* argument) { // Constants for producing the flags char *divleft = "----------------------------------[ "; char *divright = " ]----------------------------------"; CRoomIndexData &InRoom = *ch->GetInRoom (); if (InRoom.IsPetShop ()) { CRoomIndexData *pPetRoom = RoomTable.GetRoom (InRoom.vnum + 1); if (! pPetRoom) { bug ("Do_list: bad pet shop at vnum %d.", InRoom.vnum); ch->SendText ("You can't do that here.\n\r"); return; } BOOL bFound = FALSE; CCharacter *pet = pPetRoom->first_person; for ( ; pet; pet = pet->GetNextInRoom ()) { if (pet->IsPet () && pet->IsNpc ()) { if (! bFound) { bFound = TRUE; send_to_pager ("Pets for sale:\n\r", ch); } pager_printf (ch, "[%2d] %8d - %s\n\r", pet->GetLevel (), 10 * pet->GetLevel () * pet->GetLevel (), pet->GetShortDescr ()); } } if (! bFound) ch->SendText ("Sorry, we're out of pets right now.\n\r"); return; } char arg [MAX_INPUT_LENGTH]; char *rest; CObjData *obj; int cost; rest = one_argument (argument, arg); CCharacter *keeper = find_keeper (ch); if (! keeper || ! CanTrade (ch, keeper)) return; int lower = -2; int upper = -1; // Get the level limits for the flags if (is_number (arg)) { lower = atoi (arg); rest = one_argument (rest, arg); if (is_number (arg)) { upper = atoi (arg); rest = one_argument (rest, arg); } } // Fix the limits if reversed if (lower >= upper) { int temp = lower; lower = upper; upper = temp; } // Loop until you see an object higher level than char // Note that this depends on the keeper having a sorted list BOOL bFound = FALSE; POSITION pos = keeper->GetHeadCarryPos (); while (obj = keeper->GetNextCarrying (pos)) { if (obj->wear_loc == WEAR_NONE && can_see_obj (ch, *obj) && (cost = get_cost (ch, keeper, obj, TRUE)) > 0 && (arg [0] == '\0' || nifty_is_name (arg, obj->GetName ()))) { if (! bFound) { bFound = TRUE; send_to_pager ("[Lv Price] Item\n\r", ch); } if (obj->GetLevel () <= upper) { pager_printf (ch, "%s%2d%s\n\r", divleft, upper, divright); upper = -1; } if (obj->GetLevel () < lower) { pager_printf (ch, "%s%2d%s\n\r", divleft, lower, divright); lower = -1; } pager_printf (ch, "[%2d %5d] %s.\n\r", obj->GetLevel (), cost, capitalize (obj->GetShortDescr ())); } } if (lower >= 0) pager_printf (ch, "%s%2d%s\n\r", divleft, lower, divright); if (! bFound) { if (arg [0] == '\0') ch->SendText ("You can't buy anything here.\n\r"); else ch->SendText ("You can't buy that here.\n\r"); } } void do_sell (CCharacter *ch, char *argument) { char buf [MAX_STRING_LENGTH]; char arg [MAX_INPUT_LENGTH]; CObjData *obj; int cost; one_argument (argument, arg); if (arg [0] == '\0') { ch->SendText ("Sell what?\n\r"); return; } CCharacter *keeper = find_keeper (ch); if (! keeper || ! CanTrade (ch, keeper)) return; if ((obj = get_obj_carry (ch, arg)) == NULL) { act (AT_TELL, "$n tells you 'You don't have that item.'", keeper, NULL, ch, TO_VICT); ch->SetReplier (keeper); return; } if (! can_drop_obj (ch, obj)) { ch->SendText ("You can't let go of it!\n\r"); return; } if (obj->timer > 0) { act (AT_TELL, "$n tells you, '$p is depreciating in value too quickly...'", keeper, obj, ch, TO_VICT); return; } if ((cost = get_cost (ch, keeper, obj, FALSE)) <= 0) { act (AT_ACTION, "$n looks uninterested in $p.", keeper, obj, ch, TO_VICT); return; } if (cost >= keeper->GetGold ()) { act (AT_TELL, "$n tells you, '$p is worth more than I can " "afford...'", keeper, obj, ch, TO_VICT); return; } separate_obj (obj); act (AT_ACTION, "$n sells $p.", ch, obj, NULL, TO_ROOM); sprintf (buf, "You sell $p for %d gold piece%s.", cost, cost == 1 ? "" : "s"); act (AT_ACTION, buf, ch, obj, NULL, TO_CHAR); ch->AddGold (cost); keeper->AddGold (-cost); if (keeper->GetGold () < 0) keeper->SetGold (0); if (obj->item_type == ITEM_TRASH) extract_obj (obj); else { obj_from_char (obj); obj_to_char (obj, keeper, ADDBYLEVEL); } } void do_value (CCharacter *ch, char *argument) { char buf [MAX_STRING_LENGTH]; CObjData *obj; int cost; if (argument [0] == '\0') { ch->SendText ("Value what?\n\r"); return; } CCharacter *keeper = find_keeper (ch); if (! keeper || ! CanTrade (ch, keeper)) return; if ((obj = get_obj_carry (ch, argument)) == NULL) { act (AT_TELL, "$n tells you 'You don't have that item.'", keeper, NULL, ch, TO_VICT); ch->SetReplier (keeper); return; } if (! can_drop_obj (ch, obj)) { ch->SendText ("You can't let go of it!\n\r"); return; } if ((cost = get_cost (ch, keeper, obj, FALSE)) <= 0) { act (AT_ACTION, "$n looks uninterested in $p.", keeper, obj, ch, TO_VICT); return; } sprintf (buf, "$n tells you 'I'll give you %d gold coins for $p.'", cost); act (AT_TELL, buf, keeper, obj, ch, TO_VICT); ch->SetReplier (keeper); } /* * Repair a single object. Used when handling "repair all" - Gorog */ void repair_one_obj (CCharacter *ch, CCharacter *keeper, CObjData *obj, char *arg, int maxgold, char *fixstr, char*fixstr2) { char buf[MAX_STRING_LENGTH]; int cost; if (!can_drop_obj (ch, obj)) ch->SendTextf ("You can't let go of %s.\n\r", obj->GetName ()); else if ((cost = get_repaircost (keeper, obj)) < 0) { if (cost != -2) act (AT_TELL, "$n tells you, 'Sorry, I can't do anything with $p.'", keeper, obj, ch, TO_VICT); else act (AT_TELL, "$n tells you, '$p looks fine to me!'", keeper, obj, ch, TO_VICT); } /* "repair all" gets a 10% surcharge - Gorog */ else if ((cost = strcmp ("all",arg) ? cost : 11*cost/10) > ch->GetGold ()) { sprintf (buf, "$N tells you, 'It will cost %d piece%s of gold to %s %s...'", cost, cost == 1 ? "" : "s", fixstr, obj->GetName ()); act (AT_TELL, buf, ch, NULL, keeper, TO_CHAR); act (AT_TELL, "$N tells you, 'Which I see you can't afford.'", ch, NULL, keeper, TO_CHAR); } else { sprintf (buf, "$n gives $p to $N, who quickly %s it.", fixstr2); act (AT_ACTION, buf, ch, obj, keeper, TO_ROOM); sprintf (buf, "$N charges you %d gold piece%s to %s $p.", cost, cost == 1 ? "" : "s", fixstr); act (AT_ACTION, buf, ch, obj, keeper, TO_CHAR); ch->AddGold (-cost); keeper->AddGold (cost); if (keeper->GetGold () < 0) keeper->SetGold (0); else if (keeper->GetGold () > maxgold) { keeper->GetInRoom ()->GetArea ()->BoostEconomy ( keeper->GetGold () - maxgold/2); keeper->SetGold (maxgold/2); act (AT_ACTION, "$n puts some gold into a large safe.", keeper, NULL, NULL, TO_ROOM); } switch (obj->item_type) { default: ch->SendText ("For some reason, you think you got ripped off...\n\r"); break; case ITEM_ARMOR: obj->value[0] = obj->value[1]; break; case ITEM_WEAPON: obj->value[0] = INIT_WEAPON_CONDITION; break; case ITEM_WAND: case ITEM_STAFF: obj->value[2] = obj->value[1]; break; } oprog_repair_trigger (ch, obj); } } void do_repair (CCharacter *ch, char *argument) { CCharacter *keeper; CObjData *obj; char *fixstr; char *fixstr2; int maxgold; if (argument[0] == '\0') { ch->SendText ("Repair what?\n\r"); return; } if ((keeper = find_fixer (ch)) == NULL) return; maxgold = keeper->GetLevel () * keeper->GetLevel () * 100000; switch (keeper->GetMobIndex ()->rShop->shop_type) { default: case SHOP_FIX: fixstr = "repair"; fixstr2 = "repairs"; break; case SHOP_RECHARGE: fixstr = "recharge"; fixstr2 = "recharges"; break; } if (! strcmp (argument, "all")) { POSITION pos = ch->GetHeadCarryPos (); while (obj = ch->GetNextCarrying (pos)) { if (obj->wear_loc == WEAR_NONE && can_see_obj (ch, *obj) && (obj->item_type == ITEM_ARMOR || obj->item_type == ITEM_WEAPON || obj->item_type == ITEM_WAND || obj->item_type == ITEM_STAFF)) repair_one_obj (ch, keeper, obj, argument, maxgold, fixstr, fixstr2); } return; } if ((obj = get_obj_carry (ch, argument)) == NULL) { act (AT_TELL, "$n tells you 'You don't have that item.'", keeper, NULL, ch, TO_VICT); ch->SetReplier (keeper); return; } repair_one_obj (ch, keeper, obj, argument, maxgold, fixstr, fixstr2); } void appraise_all (CCharacter *ch, CCharacter *keeper, char *fixstr) { char buf [MAX_STRING_LENGTH]; CObjData *obj; int cost, total=0; POSITION pos = ch->GetHeadCarryPos (); while (obj = ch->GetNextCarrying (pos)) { if (obj->wear_loc == WEAR_NONE && can_see_obj (ch, *obj) && (obj->item_type == ITEM_ARMOR || obj->item_type == ITEM_WEAPON || obj->item_type == ITEM_WAND || obj->item_type == ITEM_STAFF)) if (! can_drop_obj (ch, obj)) ch->SendTextf ("You can't let go of %s.\n\r", obj->GetName ()); else if ((cost = get_repaircost (keeper, obj)) < 0) { if (cost != -2) act (AT_TELL, "$n tells you, 'Sorry, I can't do anything with $p.'", keeper, obj, ch, TO_VICT); else act (AT_TELL, "$n tells you, '$p looks fine to me!'", keeper, obj, ch, TO_VICT); } else { sprintf (buf, "$N tells you, 'It will cost %d piece%s of gold to %s %s'", cost, cost == 1 ? "" : "s", fixstr, obj->GetName ()); act (AT_TELL, buf, ch, NULL, keeper, TO_CHAR); total += cost; } } if (total > 0) { ch->SendText ("\n\r"); sprintf (buf, "$N tells you, 'It will cost %d piece%s of gold in total.'", total, cost == 1 ? "" : "s"); act (AT_TELL, buf, ch, NULL, keeper, TO_CHAR); strcpy (buf, "$N tells you, 'Remember there is a 10% surcharge for repair all.'"); act (AT_TELL, buf, ch, NULL, keeper, TO_CHAR); } } void do_appraise (CCharacter *ch, char *argument) { char buf[MAX_STRING_LENGTH]; char arg[MAX_INPUT_LENGTH]; CCharacter *keeper; CObjData *obj; int cost; char *fixstr; one_argument (argument, arg); if (arg[0] == '\0') { ch->SendText ("Appraise what?\n\r"); return; } if ((keeper = find_fixer (ch)) == NULL) return; switch (keeper->GetMobIndex ()->rShop->shop_type) { default: case SHOP_FIX: fixstr = "repair"; break; case SHOP_RECHARGE: fixstr = "recharge"; break; } if (!strcmp (arg, "all")) { appraise_all (ch, keeper, fixstr); return; } if ((obj = get_obj_carry (ch, arg)) == NULL) { act (AT_TELL, "$n tells you 'You don't have that item.'", keeper, NULL, ch, TO_VICT); ch->SetReplier (keeper); return; } if (!can_drop_obj (ch, obj)) { ch->SendText ("You can't let go of it.\n\r"); return; } if ((cost = get_repaircost (keeper, obj)) < 0) { if (cost != -2) act (AT_TELL, "$n tells you, 'Sorry, I can't do anything with $p.'", keeper, obj, ch, TO_VICT); else act (AT_TELL, "$n tells you, '$p looks fine to me!'", keeper, obj, ch, TO_VICT); return; } sprintf (buf, "$N tells you, 'It will cost %d piece%s of gold to %s that...'", cost, cost == 1 ? "" : "s", fixstr); act (AT_TELL, buf, ch, NULL, keeper, TO_CHAR); if (cost > ch->GetGold ()) act (AT_TELL, "$N tells you, 'Which I see you can't afford.'", ch, NULL, keeper, TO_CHAR); return; } /* ------------------ Shop Building and Editing Section ----------------- */ void do_makeshop (CCharacter *ch, char *argument) { CShopData *shop; int vnum; CMobIndexData *mob; if (!argument || argument[0] == '\0') { ch->SendText ("Usage: makeshop <mobvnum>\n\r"); return; } vnum = atoi (argument); if ((mob = MobTable.GetMob (vnum)) == NULL) { ch->SendText ("Mobile not found.\n\r"); return; } if (!can_medit (ch, mob)) return; if (mob->pShop) { ch->SendText ("This mobile already has a shop.\n\r"); return; } shop = new CShopData; LINK (shop, first_shop, last_shop); shop->keeper = vnum; shop->profit_buy = 120; shop->profit_sell = 90; shop->open_hour = 0; shop->close_hour = 23; mob->pShop = shop; ch->SendText ("Done.\n\r"); return; } void do_shopset (CCharacter *ch, char *argument) { CShopData *shop; CMobIndexData *mob, *mob2; char arg1 [MAX_INPUT_LENGTH]; char arg2 [MAX_INPUT_LENGTH]; int vnum; int value; argument = one_argument (argument, arg1); argument = one_argument (argument, arg2); if (arg1[0] == '\0' || arg2[0] == '\0') { ch->SendText ("Usage: shopset <mob vnum> <field> value\n\r"); ch->SendText ("\n\rField being one of:\n\r"); ch->SendText (" buy0 buy1 buy2 buy3 buy4 buy sell open close keeper\n\r"); return; } vnum = atoi (arg1); if ((mob = MobTable.GetMob (vnum)) == NULL) { ch->SendText ("Mobile not found.\n\r"); return; } if (!can_medit (ch, mob)) return; if (!mob->pShop) { ch->SendText ("This mobile doesn't keep a shop.\n\r"); return; } shop = mob->pShop; value = atoi (argument); if (!str_cmp (arg2, "buy0")) { if (!is_number (argument)) value = get_otype (argument); if (value < 0 || value > MAX_ITEM_TYPE) { ch->SendText ("Invalid item type!\n\r"); return; } shop->buy_type[0] = value; ch->SendText ("Done.\n\r"); return; } if (!str_cmp (arg2, "buy1")) { if (!is_number (argument)) value = get_otype (argument); if (value < 0 || value > MAX_ITEM_TYPE) { ch->SendText ("Invalid item type!\n\r"); return; } shop->buy_type[1] = value; ch->SendText ("Done.\n\r"); return; } if (!str_cmp (arg2, "buy2")) { if (!is_number (argument)) value = get_otype (argument); if (value < 0 || value > MAX_ITEM_TYPE) { ch->SendText ("Invalid item type!\n\r"); return; } shop->buy_type[2] = value; ch->SendText ("Done.\n\r"); return; } if (!str_cmp (arg2, "buy3")) { if (!is_number (argument)) value = get_otype (argument); if (value < 0 || value > MAX_ITEM_TYPE) { ch->SendText ("Invalid item type!\n\r"); return; } shop->buy_type[3] = value; ch->SendText ("Done.\n\r"); return; } if (!str_cmp (arg2, "buy4")) { if (!is_number (argument)) value = get_otype (argument); if (value < 0 || value > MAX_ITEM_TYPE) { ch->SendText ("Invalid item type!\n\r"); return; } shop->buy_type[4] = value; ch->SendText ("Done.\n\r"); return; } if (!str_cmp (arg2, "buy")) { if (value <= (shop->profit_sell+5) || value > 1000) { ch->SendText ("Out of range.\n\r"); return; } shop->profit_buy = value; ch->SendText ("Done.\n\r"); return; } if (!str_cmp (arg2, "sell")) { if (value < 0 || value >= (shop->profit_buy-5)) { ch->SendText ("Out of range.\n\r"); return; } shop->profit_sell = value; ch->SendText ("Done.\n\r"); return; } if (!str_cmp (arg2, "open")) { if (value < 0 || value > 23) { ch->SendText ("Out of range.\n\r"); return; } shop->open_hour = value; ch->SendText ("Done.\n\r"); return; } if (!str_cmp (arg2, "close")) { if (value < 0 || value > 23) { ch->SendText ("Out of range.\n\r"); return; } shop->close_hour = value; ch->SendText ("Done.\n\r"); return; } if (!str_cmp (arg2, "keeper")) { if ((mob2 = MobTable.GetMob (vnum)) == NULL) { ch->SendText ("Mobile not found.\n\r"); return; } if (!can_medit (ch, mob)) return; if (mob2->pShop) { ch->SendText ("That mobile already has a shop.\n\r"); return; } mob->pShop = NULL; mob2->pShop = shop; shop->keeper = value; ch->SendText ("Done.\n\r"); return; } do_shopset (ch, ""); return; } void do_shopstat (CCharacter *ch, char *argument) { CShopData *shop; CMobIndexData *mob; int vnum; if (argument[0] == '\0') { ch->SendText ("Usage: shopstat <keeper vnum>\n\r"); return; } vnum = atoi (argument); if ((mob = MobTable.GetMob (vnum)) == NULL) { ch->SendText ("Mobile not found.\n\r"); return; } if (!mob->pShop) { ch->SendText ("This mobile doesn't keep a shop.\n\r"); return; } shop = mob->pShop; ch->SendTextf ("Keeper: %d %s\n\r", shop->keeper, mob->GetShortDescr ()); ch->SendTextf ("buy0 [%s] buy1 [%s] buy2 [%s] buy3 [%s] buy4 [%s]\n\r", o_types[shop->buy_type[0]], o_types[shop->buy_type[1]], o_types[shop->buy_type[2]], o_types[shop->buy_type[3]], o_types[shop->buy_type[4]]); ch->SendTextf ("Profit: buy %3d%% sell %3d%%\n\r", shop->profit_buy, shop->profit_sell); ch->SendTextf ("Hours: open %2d close %2d\n\r", shop->open_hour, shop->close_hour); return; } void do_shops (CCharacter *ch, char *argument) { CShopData *shop; if (!first_shop) { ch->SendText ("There are no shops.\n\r"); return; } set_char_color (AT_NOTE, ch); for (shop = first_shop; shop; shop = shop->GetNext ()) ch->SendTextf ("Keeper: %5d Buy: %3d Sell: %3d Open: %2d Close: %2d Buy: %2d %2d %2d %2d %2d\n\r", shop->keeper, shop->profit_buy, shop->profit_sell, shop->open_hour, shop->close_hour, shop->buy_type[0], shop->buy_type[1], shop->buy_type[2], shop->buy_type[3], shop->buy_type[4]); return; } /* -------------- Repair Shop Building and Editing Section -------------- */ void do_makerepair (CCharacter *ch, char *argument) { CRepairShopData *repair; int vnum; CMobIndexData *mob; if (!argument || argument[0] == '\0') { ch->SendText ("Usage: makerepair <mobvnum>\n\r"); return; } vnum = atoi (argument); if ((mob = MobTable.GetMob (vnum)) == NULL) { ch->SendText ("Mobile not found.\n\r"); return; } if (!can_medit (ch, mob)) return; if (mob->rShop) { ch->SendText ("This mobile already has a repair shop.\n\r"); return; } repair = new CRepairShopData; LINK (repair, first_repair, last_repair); repair->keeper = vnum; repair->profit_fix = 100; repair->shop_type = SHOP_FIX; repair->open_hour = 0; repair->close_hour = 23; mob->rShop = repair; ch->SendText ("Done.\n\r"); return; } void do_repairset (CCharacter *ch, char *argument) { CRepairShopData *repair; CMobIndexData *mob, *mob2; char arg1 [MAX_INPUT_LENGTH]; char arg2 [MAX_INPUT_LENGTH]; int vnum; int value; argument = one_argument (argument, arg1); argument = one_argument (argument, arg2); if (arg1[0] == '\0' || arg2[0] == '\0') { ch->SendText ("Usage: repairset <mob vnum> <field> value\n\r"); ch->SendText ("\n\rField being one of:\n\r"); ch->SendText (" fix0 fix1 fix2 profit type open close keeper\n\r"); return; } vnum = atoi (arg1); if ((mob = MobTable.GetMob (vnum)) == NULL) { ch->SendText ("Mobile not found.\n\r"); return; } if (!can_medit (ch, mob)) return; if (!mob->rShop) { ch->SendText ("This mobile doesn't keep a repair shop.\n\r"); return; } repair = mob->rShop; value = atoi (argument); if (!str_cmp (arg2, "fix0")) { if (!is_number (argument)) value = get_otype (argument); if (value < 0 || value > MAX_ITEM_TYPE) { ch->SendText ("Invalid item type!\n\r"); return; } repair->fix_type[0] = value; ch->SendText ("Done.\n\r"); return; } if (!str_cmp (arg2, "fix1")) { if (!is_number (argument)) value = get_otype (argument); if (value < 0 || value > MAX_ITEM_TYPE) { ch->SendText ("Invalid item type!\n\r"); return; } repair->fix_type[1] = value; ch->SendText ("Done.\n\r"); return; } if (!str_cmp (arg2, "fix2")) { if (!is_number (argument)) value = get_otype (argument); if (value < 0 || value > MAX_ITEM_TYPE) { ch->SendText ("Invalid item type!\n\r"); return; } repair->fix_type[2] = value; ch->SendText ("Done.\n\r"); return; } if (!str_cmp (arg2, "profit")) { if (value < 1 || value > 1000) { ch->SendText ("Out of range.\n\r"); return; } repair->profit_fix = value; ch->SendText ("Done.\n\r"); return; } if (!str_cmp (arg2, "type")) { if (value < 1 || value > 2) { ch->SendText ("Out of range.\n\r"); return; } repair->shop_type = value; ch->SendText ("Done.\n\r"); return; } if (!str_cmp (arg2, "open")) { if (value < 0 || value > 23) { ch->SendText ("Out of range.\n\r"); return; } repair->open_hour = value; ch->SendText ("Done.\n\r"); return; } if (!str_cmp (arg2, "close")) { if (value < 0 || value > 23) { ch->SendText ("Out of range.\n\r"); return; } repair->close_hour = value; ch->SendText ("Done.\n\r"); return; } if (!str_cmp (arg2, "keeper")) { if ((mob2 = MobTable.GetMob (vnum)) == NULL) { ch->SendText ("Mobile not found.\n\r"); return; } if (!can_medit (ch, mob)) return; if (mob2->rShop) { ch->SendText ("That mobile already has a repair shop.\n\r"); return; } mob->rShop = NULL; mob2->rShop = repair; repair->keeper = value; ch->SendText ("Done.\n\r"); return; } do_repairset (ch, ""); return; } void do_repairstat (CCharacter *ch, char *argument) { CRepairShopData *repair; CMobIndexData *mob; int vnum; if (argument[0] == '\0') { ch->SendText ("Usage: repairstat <keeper vnum>\n\r"); return; } vnum = atoi (argument); if ((mob = MobTable.GetMob (vnum)) == NULL) { ch->SendText ("Mobile not found.\n\r"); return; } if (!mob->rShop) { ch->SendText ("This mobile doesn't keep a repair shop.\n\r"); return; } repair = mob->rShop; ch->SendTextf ("Keeper: %d %s\n\r", repair->keeper, mob->GetShortDescr ()); ch->SendTextf ("fix0 [%s] fix1 [%s] fix2 [%s]\n\r", o_types[repair->fix_type[0]], o_types[repair->fix_type[1]], o_types[repair->fix_type[2]]); ch->SendTextf ("Profit: %3d%% Type: %d\n\r", repair->profit_fix, repair->shop_type); ch->SendTextf ("Hours: open %2d close %2d\n\r", repair->open_hour, repair->close_hour); return; } void do_repairshops (CCharacter *ch, char *argument) { CRepairShopData *repair; if (!first_repair) { ch->SendText ("There are no repair shops.\n\r"); return; } set_char_color (AT_NOTE, ch); for (repair = first_repair; repair; repair = repair->GetNext ()) ch->SendTextf ("Keeper: %5d Profit: %3d Type: %d Open: %2d Close: %2d Fix: %2d %2d %2d\n\r", repair->keeper, repair->profit_fix, repair->shop_type, repair->open_hour, repair->close_hour, repair->fix_type[0], repair->fix_type[1], repair->fix_type[2]); return; }