/****************************************************************************
* [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;
}