/**************************************************************************** * [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame | \\._.// * * -----------------------------------------------------------| (0...0) * * SMAUG 1.4 (C) 1994, 1995, 1996, 1998 by Derek Snider | ).:.( * * -----------------------------------------------------------| {o o} * * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus, | / ' ' \ * * Scryn, Rennard, Swordbearer, Gorog, Grishnakh, Nivek, |~'~.VxvxV.~'~* * Tricops and Fireblade | * * ------------------------------------------------------------------------ * * 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 St{rfeldt, Tom Madsen, and Katja Nyboe. * * ------------------------------------------------------------------------ * * Shop and repair shop module * ****************************************************************************/ #include <sys/types.h> #include <stdio.h> #include <string.h> #include <time.h> #include "mud.h" /* * Local functions */ #define CD CHAR_DATA CD *find_keeper args((CHAR_DATA * ch)); CD *find_fixer args((CHAR_DATA * ch)); int get_cost args((CHAR_DATA * ch, CHAR_DATA * keeper, OBJ_DATA * obj, int fBuy)); int get_repaircost args((CHAR_DATA * keeper, OBJ_DATA * obj)); #undef CD /* * Shopping commands. */ CHAR_DATA *find_keeper(CHAR_DATA * ch) { char buf[MSL]; CHAR_DATA *keeper, *whof; SHOP_DATA *pShop; int speakswell; pShop = NULL; for (keeper = ch->in_room->first_person; keeper; keeper = keeper->next_in_room) if (IS_NPC(keeper) && (pShop = keeper->pIndexData->pShop) != NULL) break; if (!pShop) { send_to_char("You can't do that here.\n\r", ch); return NULL; } /* * Disallow sales during battle */ if ((whof = who_fighting(keeper)) != NULL) { if (whof == ch) send_to_char("I don't think that's a good idea...\n\r", ch); else do_say(keeper, "I'm too busy for that!"); return NULL; } if (who_fighting(ch)) { ch_printf(ch, "%s doesn't seem to want to get involved.\n\r", PERS(keeper, ch)); return NULL; } /* * Check to see if show is open. * Supports closing times after midnight */ if (pShop->open_hour > pShop->close_hour) { if (gethour() < pShop->open_hour && gethour() > pShop->close_hour) { do_say(keeper, "Sorry, come back later."); return NULL; } } else { if (gethour() < pShop->open_hour) { do_say(keeper, "Sorry, come back later."); return NULL; } if (gethour() > pShop->close_hour) { do_say(keeper, "Sorry, come back tomorrow."); return NULL; } } if (keeper->position == POS_SLEEPING) { send_to_char("While they're asleep?\n\r", ch); return NULL; } if (keeper->position < POS_SLEEPING) { send_to_char("I don't think they can hear you...\n\r", ch); 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; } speakswell = UMIN(knows_language(keeper, ch->speaking, ch), knows_language(ch, ch->speaking, keeper)); if ((number_percent() % 65) > speakswell) { if (speakswell > 60) sprintf(buf, "%s Could you repeat that? I didn't quite catch it.", ch->name); else if (speakswell > 50) sprintf(buf, "%s Could you say that a little more clearly please?", ch->name); else if (speakswell > 40) sprintf(buf, "%s Sorry... What was that you wanted?", ch->name); else sprintf(buf, "%s I can't understand you.", ch->name); do_tell(keeper, buf); return NULL; } return keeper; } /* * repair commands. */ CHAR_DATA *find_fixer(CHAR_DATA * ch) { char buf[MSL]; CHAR_DATA *keeper, *whof; REPAIR_DATA *rShop; int speakswell; rShop = NULL; for (keeper = ch->in_room->first_person; keeper; keeper = keeper->next_in_room) if (IS_NPC(keeper) && IN_SAME_ROOM(keeper, ch) && (rShop = keeper->pIndexData->rShop) != NULL) break; if (!rShop) { send_to_char("You can't do that here.\n\r", ch); return NULL; } /* * Disallow sales during battle */ if ((whof = who_fighting(keeper)) != NULL) { if (whof == ch) send_to_char("I don't think that's a good idea...\n\r", ch); else do_say(keeper, "I'm too busy for that!"); return NULL; } /* According to rlog, this is the second time I've done this * so mobiles can repair in combat. -- Blod, 1/98 */ if (!IS_NPC(ch) && who_fighting(ch)) { ch_printf(ch, "%s doesn't seem to want to get involved.\n\r", PERS(keeper, ch)); return NULL; } /* * Check to see if show is open. * Supports closing times after midnight */ if (rShop->open_hour > rShop->close_hour) { if (gethour() < rShop->open_hour && gethour() > rShop->close_hour) { do_say(keeper, "Sorry, come back later."); return NULL; } } else { if (gethour() < rShop->open_hour) { do_say(keeper, "Sorry, come back later."); return NULL; } if (gethour() > rShop->close_hour) { do_say(keeper, "Sorry, come back tomorrow."); return NULL; } } if (keeper->position == POS_SLEEPING) { send_to_char("While they're asleep?\n\r", ch); return NULL; } if (keeper->position < POS_SLEEPING) { send_to_char("I don't think they can hear you...\n\r", ch); 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; } speakswell = UMIN(knows_language(keeper, ch->speaking, ch), knows_language(ch, ch->speaking, keeper)); if ((number_percent() % 65) > speakswell) { if (speakswell > 60) sprintf(buf, "%s Could you repeat that? I didn't quite catch it.", ch->name); else if (speakswell > 50) sprintf(buf, "%s Could you say that a little more clearly please?", ch->name); else if (speakswell > 40) sprintf(buf, "%s Sorry... What was that you wanted?", ch->name); else sprintf(buf, "%s I can't understand you.", ch->name); do_tell(keeper, buf); return NULL; } return keeper; } int get_cost(CHAR_DATA * ch, CHAR_DATA * keeper, OBJ_DATA * obj, int fBuy) { SHOP_DATA *pShop; int cost; int tax; int taxk; bool richcustomer; int profitmod; if (!obj || (pShop = keeper->pIndexData->pShop) == NULL) return 0; richcustomer = FALSE; if (fBuy == 1 || fBuy == 2) { profitmod = 0; cost = (int) (obj->cost * UMAX((pShop->profit_sell + 1), pShop->profit_buy + profitmod)) / 100; /* Thanks to Nick Gammon for pointing out this line (it was the first line in this block, making it useless) */ switch (ch->race) /* racism... should compare against shopkeeper's race */ { case (1): cost /= 1.1; break; /* elf */ case (2): cost /= 0.97; break; /* dwarf */ case (3): cost /= 1.02; break; /* halfling */ case (4): cost /= 1.08; break; /* pixie */ case (6): cost /= 0.92; break; /* half-ogre */ case (7): cost /= 0.94; break; /* half-orc */ case (8): cost /= 0.90; break; /* half-troll */ case (9): cost /= 1.04; break; /* half-elf */ case (10): cost /= 1.06; break; /* gith */ } } else { OBJ_DATA *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; } } /* Checks to see if an obj is on the merchants vnums and if so, will check vnums and cvnum against eachother to see if they are a copy. -- Xerves 12/99 */ for (obj2 = keeper->first_carrying; obj2; obj2 = obj2->next_content) { if (obj->pIndexData->vnum == obj2->pIndexData->vnum) { cost = 0; break; } if (obj2->pIndexData->vnum >= 12100 || obj2->pIndexData->vnum <= 13100) { if (obj2->pIndexData->cvnum == obj->pIndexData->vnum) { cost = 0; break; } } } } if (fBuy == 2) { if (ch->in_room->area->kingdom > 1) { taxk = (cost * kingdom_table[ch->in_room->area->kingdom]->salestax) / 1000; cost = cost + taxk; tax = (cost * ch->in_room->area->salestax) / 1000; cost = cost + tax; } } return cost; } int get_repaircost(CHAR_DATA * keeper, OBJ_DATA * obj) { REPAIR_DATA *rShop; int cost; int itype; bool found; if (!obj || (rShop = keeper->pIndexData->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 (IS_SET(obj->wear_flags, ITEM_WEAR_SHIELD)) { if (obj->value[0] == obj->value[1]) cost = -2; else cost = cost * (obj->value[1] - obj->value[0]) / obj->value[1]; } else { if (obj->value[3] == INIT_ARMOR_CONDITION) cost = -2; else cost = cost * (1000 - obj->value[3]) / INIT_ARMOR_CONDITION; } break; case ITEM_WEAPON: if (INIT_ARMOR_CONDITION == obj->value[0]) cost = -2; else cost = cost * (1000 - obj->value[0]) / INIT_ARMOR_CONDITION; break; case ITEM_SHEATH: if (obj->value[3] == INIT_ARMOR_CONDITION) cost = -2; else cost = cost * (INIT_ARMOR_CONDITION - obj->value[3]); break; } } return cost; } /***************************************** Below five functions are used in shopkeeper options for their Owners (Merchant Job) -- Xerves *****************************************/ void do_keeperstat(CHAR_DATA * ch, char *argument) { SHOP_DATA *shop; CHAR_DATA *keeper; int found = 0; if (IS_NPC(ch)) { send_to_char("Mobs cannot have shopkeepers\n\r", ch); return; } if (!ch->pcdata || !ch->pcdata->keeper || (ch->pcdata->caste < 7)) { send_to_char("You need to have a shop keeper to see its stats.\n\r", ch); return; } for (keeper = ch->in_room->first_person; keeper; keeper = keeper->next_in_room) { if ((IS_NPC(keeper)) && (xIS_SET(keeper->act, ACT_CASTEMOB)) && (keeper->pIndexData->vnum == ch->pcdata->keeper)) { found = 1; break; } } if (found == 0) { send_to_char("Either you don't have a shopkeeper or you are not in the room with it\n\r", ch); return; } if (!keeper->pIndexData->pShop) { send_to_char("This mobile doesn't keep a shop.\n\r", ch); return; } shop = keeper->pIndexData->pShop; ch_printf_color(ch, "&G&WKeeper: &c&w%d %s\n\r", shop->keeper, keeper->short_descr); ch_printf_color(ch, "&G&Wbuy0 &c&w[%s] &G&Wbuy1 &c&w[%s] &G&Wbuy2 &c&w[%s] \n\r&G&Wbuy3 &c&w[%s] &G&Wbuy4 &c&w[%s] &G&Wgold &c&w[&Y%d&c&w]\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]], keeper->gold); ch_printf_color(ch, "&G&WProfit: &c&wbuy &R%3d%% &c&wsell &R%3d%%\n\r", shop->profit_buy, shop->profit_sell); ch_printf_color(ch, "&G&WHours: &c&wopen &R%2d &c&wclose &R%2d\n\r", shop->open_hour, shop->close_hour); ch_printf_color(ch, "&G&WMinGold: &Y%d &G&WMaxGold: &Y%d &G&WLimitGold: &Y%d\n\r", keeper->pIndexData->m1, keeper->pIndexData->m2, keeper->pIndexData->m3); ch_printf_color(ch, "&G&WHoldamt: &g&w%d\n\r", keeper->pIndexData->m6); return; } void do_keeperset(CHAR_DATA * ch, char *argument) { SHOP_DATA *shop; CHAR_DATA *keeper; int found = 0; char arg1[MIL]; int value; argument = one_argument(argument, arg1); if (IS_NPC(ch)) { send_to_char("Mobs cannot have a shopkeeper\n\r", ch); return; } if (!ch->pcdata || !ch->pcdata->keeper || (ch->pcdata->caste < 7)) { send_to_char("You need to have a shop keeper to see its stats.\n\r", ch); return; } for (keeper = ch->in_room->first_person; keeper; keeper = keeper->next_in_room) { if ((IS_NPC(keeper)) && (xIS_SET(keeper->act, ACT_CASTEMOB)) && (keeper->pIndexData->vnum == ch->pcdata->keeper)) { found = 1; break; } } if (found == 0) { send_to_char("Either you don't have a shopkeeper or you are not in the room with it\n\r", ch); return; } if (!keeper->pIndexData->pShop) { send_to_char("This mobile doesn't keep a shop.\n\r", ch); bug("Mob %d is not a keeper, but set as a player keeper", keeper->pIndexData->vnum); return; } if (arg1[0] == '\0') { send_to_char("Usage: keeperset <field> value\n\r", ch); send_to_char("\n\rField being one of:\n\r", ch); send_to_char("buy0 buy1 buy2 buy3 buy4 buy sell open close\n\r", ch); send_to_char("gold0 gold1 gold2\n\r", ch); send_to_char("holdamt\n\r", ch); return; } shop = keeper->pIndexData->pShop; value = atoi(argument); if (!str_cmp(arg1, "buy0")) { if (!is_number(argument)) value = get_otype(argument); if (value < 0 || value > MAX_ITEM_TYPE) { send_to_char("Invalid item type!\n\r", ch); return; } shop->buy_type[0] = value; send_to_char("Done.\n\r", ch); return; } if (!str_cmp(arg1, "buy1")) { if (!is_number(argument)) value = get_otype(argument); if (value < 0 || value > MAX_ITEM_TYPE) { send_to_char("Invalid item type!\n\r", ch); return; } shop->buy_type[1] = value; send_to_char("Done.\n\r", ch); return; } if (!str_cmp(arg1, "buy2")) { if (!is_number(argument)) value = get_otype(argument); if (value < 0 || value > MAX_ITEM_TYPE) { send_to_char("Invalid item type!\n\r", ch); return; } shop->buy_type[2] = value; send_to_char("Done.\n\r", ch); return; } if (!str_cmp(arg1, "buy3")) { if (!is_number(argument)) value = get_otype(argument); if (value < 0 || value > MAX_ITEM_TYPE) { send_to_char("Invalid item type!\n\r", ch); return; } shop->buy_type[3] = value; send_to_char("Done.\n\r", ch); return; } if (!str_cmp(arg1, "buy4")) { if (!is_number(argument)) value = get_otype(argument); if (value < 0 || value > MAX_ITEM_TYPE) { send_to_char("Invalid item type!\n\r", ch); return; } shop->buy_type[4] = value; send_to_char("Done.\n\r", ch); return; } if (!str_cmp(arg1, "buy")) { if (value <= (shop->profit_sell + 5) || value > 1000) { send_to_char("Out of range.\n\r", ch); return; } shop->profit_buy = value; send_to_char("Done.\n\r", ch); return; } if (!str_cmp(arg1, "sell")) { if (value < 0 || value >= (shop->profit_buy - 5)) { send_to_char("Out of range.\n\r", ch); return; } shop->profit_sell = value; send_to_char("Done.\n\r", ch); return; } if (!str_cmp(arg1, "open")) { if (value < 0 || value > 23) { send_to_char("Out of range.\n\r", ch); return; } shop->open_hour = value; send_to_char("Done.\n\r", ch); return; } if (!str_cmp(arg1, "close")) { if (value < 0 || value > 23) { send_to_char("Out of range.\n\r", ch); return; } shop->close_hour = value; send_to_char("Done.\n\r", ch); return; } if (!str_cmp(arg1, "gold0")) { if (value > keeper->pIndexData->m2) { send_to_char("Your minimum cannot be higher than the maximum\n\r", ch); return; } if (value < 1) { send_to_char("Value needs to be 1 or greater\n\r", ch); return; } keeper->pIndexData->m1 = value; send_to_char("Done.\n\r", ch); return; } if (!str_cmp(arg1, "gold1")) { if (value < keeper->pIndexData->m1) { send_to_char("You maximum cannot be lower than the minimum\n\r", ch); return; } if (value < 1) { send_to_char("Value needs to be 1 or greater\n\r", ch); return; } keeper->pIndexData->m2 = value; send_to_char("Done.\n\r", ch); return; } if (!str_cmp(arg1, "gold2")) { if (value < 1) { send_to_char("Value needs to be 1 or greater\n\r", ch); return; } keeper->pIndexData->m3 = value; send_to_char("Done.\n\r", ch); return; } if (!str_cmp(arg1, "holdamt")) { if (value < 1 || value > 300) { send_to_char("Range is 1 to 300\n\r", ch); return; } keeper->pIndexData->m6 = value; send_to_char("Done.\n\r", ch); return; } do_keeperset(ch, ""); return; } void do_goldtake(CHAR_DATA * ch, char *argument) { CHAR_DATA *keeper; char arg[MIL]; int found = 0; int amount; argument = one_argument(argument, arg); if (IS_NPC(ch)) { send_to_char("Mobs cannot have shopkeepers\n\r", ch); return; } if (!ch->pcdata || !ch->pcdata->keeper || (ch->pcdata->caste < 7)) { send_to_char("You need to have a shop keeper to exchange cash.\n\r", ch); return; } for (keeper = ch->in_room->first_person; keeper; keeper = keeper->next_in_room) { if ((IS_NPC(keeper)) && (xIS_SET(keeper->act, ACT_CASTEMOB)) && (keeper->pIndexData->vnum == ch->pcdata->keeper)) { found = 1; break; } } if (found == 0) { send_to_char("Either you don't have a shopkeeper or you are not in the room with it\n\r", ch); return; } if (arg[0] == '\0') { send_to_char("Syntax: goldtake <amount>\n\r", ch); return; } amount = atoi(arg); if (!is_number(arg)) { send_to_char("Amount needs to be a number\n\r", ch); return; } if (amount > keeper->gold || amount > keeper->pIndexData->gold) { send_to_char("Your keeper does not have that much gold.\n\r", ch); return; } ch->gold += amount; keeper->pIndexData->gold -= amount; keeper->gold -= amount; send_to_char("Amount transfered\n\r", ch); return; } void do_goldgive(CHAR_DATA * ch, char *argument) { CHAR_DATA *keeper; char arg[MIL]; int found = 0; int amount; argument = one_argument(argument, arg); if (IS_NPC(ch)) { send_to_char("Mobs cannot have shopkeepers\n\r", ch); return; } if (!ch->pcdata || !ch->pcdata->keeper || (ch->pcdata->caste < 7)) { send_to_char("You need to have a shop keeper to exchange cash.\n\r", ch); return; } for (keeper = ch->in_room->first_person; keeper; keeper = keeper->next_in_room) { if ((IS_NPC(keeper)) && (xIS_SET(keeper->act, ACT_CASTEMOB)) && (keeper->pIndexData->vnum == ch->pcdata->keeper)) { found = 1; break; } } if (found == 0) { send_to_char("Either you don't have a shopkeeper or you are not in the room with it\n\r", ch); return; } if (arg[0] == '\0') { send_to_char("Syntax: goldgive <amount>\n\r", ch); return; } amount = atoi(arg); if (!is_number(arg)) { send_to_char("Amount needs to be a number\n\r", ch); return; } if (amount > ch->gold) { send_to_char("You do not have that much gold on you.\n\r", ch); return; } ch->gold -= amount; keeper->pIndexData->gold += amount; keeper->gold += amount; send_to_char("Amount transfered\n\r", ch); return; } void do_makekeeper(CHAR_DATA * ch, char *argument) { char arg1[MIL]; char arg2[MIL]; int amount; CHAR_DATA *victim; if (IS_NPC(ch)) { send_to_char("Mobs cannot give a player a keeper.\n\r", ch); return; } if (argument[0] == '\0') { send_to_char("Syntax: makekeeper <char> <vnum>\n\r", ch); return; } argument = one_argument(argument, arg1); argument = one_argument(argument, arg2); if (arg1 == '\0' || arg2 == '\0') { send_to_char("Syntax: makekeeper <char> <vnum>\n\r", ch); return; } if ((victim = get_char_world(ch, arg1)) == NULL) { send_to_char("They aren't here.\n\r", ch); return; } if (IS_NPC(victim)) { send_to_char("NOT ON NPCs.\n\r", ch); return; } if (get_trust(ch) <= get_trust(victim) && ch != victim) { send_to_char("Don't do that AGAIN!.\n\r", ch); return; } if (!is_number(arg2)) { send_to_char("Syntax: makekeeper <char> <vnum>\n\r", ch); return; } amount = atoi(arg2); if (amount < 1 || amount > MAX_VNUM) { send_to_char("Not a valid vnum\n\r", ch); return; } victim->pcdata->keeper = amount; send_to_char("Keeper set\n\r", ch); send_to_char("You now have a keeper\n\r", victim); return; } void do_pcshops(CHAR_DATA * ch, char *argument) { SHOP_DATA *shop; MOB_INDEX_DATA *keeper; if (!first_shop) { send_to_char("There are no shops.\n\r", ch); return; } set_char_color(AT_NOTE, ch); send_to_char("--------------------------------------------------------------------------\n\r", ch); for (shop = first_shop; shop; shop = shop->next) { if ((keeper = get_mob_index(shop->keeper)) == NULL) { bug("Shop %d found, but keeper doesn't exsist", shop->keeper); send_to_char("Error, returning out of pcshops", ch); } if (xIS_SET(keeper->act, ACT_CASTEMOB)) { ch_printf(ch, "&GKeeper: %5d &G&WBuy: &B%3d &G&WSell: &B%3d &G&WOpen: &C%2d &G&WClose: &C%2d &G&WBuy: &c%2d %2d %2d %2d %2d\n\r &G&WMinGold: &Y%-8d &G&WMaxGold: &Y%-8d &G&WLimGold: &Y%-8d\n\r &G&WMinLevel: &c&w%2d &G&WMaxlevel: &c&w%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], keeper->m1, keeper->m2, keeper->m3, keeper->m4, keeper->m5); send_to_char("&G--------------------------------------------------------------------------\n\r", ch); } } return; } void do_buy(CHAR_DATA * ch, char *argument) { char arg[MIL]; int maxgold; int ctax = 0; int tax = 0; int taxk = 0; TOWN_DATA *town; int cost; TOWN_DATA *dtown; int level; argument = one_argument(argument, arg); if (arg[0] == '\0') { send_to_char("Buy what?\n\r", ch); return; } if (xIS_SET(ch->in_room->room_flags, ROOM_MOUNT_SHOP)) { char buf[MSL]; CHAR_DATA *mount; ROOM_INDEX_DATA *pRoomIndexNext; ROOM_INDEX_DATA *in_room; if (IS_NPC(ch)) return; pRoomIndexNext = get_room_index(ch->in_room->vnum + 1); if (!pRoomIndexNext) { bug("Do_buy: bad mount shop at vnum %d.", ch->in_room->vnum); send_to_char("Sorry, you can't buy that here.\n\r", ch); return; } in_room = ch->in_room; ch->in_room = pRoomIndexNext; mount = get_char_room_new(ch, arg, 1); ch->in_room = in_room; if (mount == NULL || !IS_NPC(mount) || !xIS_SET(mount->act, ACT_MOUNTSAVE)) { send_to_char("Sorry, you can't buy that here.\n\r", ch); return; } if (xIS_SET(ch->act, PLR_BOUGHT_MOUNT)) { send_to_char("You already have a mount\n\r", ch); return; } if (ch->in_room->area->kingdom > 1) { tax = kingdom_table[ch->in_room->area->kingdom]->salestax; taxk = ch->in_room->area->salestax; } else { tax = 0; taxk = 0; } cost = mount->m2; if (ch->race == RACE_HOBBIT) cost = cost * 85 / 100; if (!IS_NPC(ch) && LEARNED(ch, gsn_haggling) > 0) { level = POINT_LEVEL(LEARNED(ch, gsn_haggling), MASTERED(ch, gsn_haggling)); cost = cost * (100-(level/2)) / 100; } ctax = (cost * tax) / 1000; taxk = (cost * taxk) / 1000; if (ch->gold < (mount->m2 + ctax + taxk)) { send_to_char("You can't afford it.\n\r", ch); return; } if (!IS_NPC(ch) && LEARNED(ch, gsn_haggling) > 0) learn_from_success(ch, gsn_haggling, NULL); maxgold = cost; ch->gold -= (maxgold + ctax + taxk); if (IN_WILDERNESS(ch)) { if ((town = find_town(ch->coord->x, ch->coord->y, ch->map)) != NULL) { if (tax) { if ((dtown = find_town(ch->coord->x, ch->coord->y, ch->map)) != NULL) { if ((get_current_hold(dtown) + (ctax/100)) <= dtown->hold) dtown->coins += ctax; } } if (taxk) { if ((get_current_hold(town) + (taxk/100)) <= town->hold) town->coins += taxk; } } } boost_economy(ch->in_room->area, maxgold); mount = create_mobile(mount->pIndexData); xSET_BIT(ch->act, PLR_BOUGHT_MOUNT); xSET_BIT(mount->act, ACT_MOUNTSAVE); xSET_BIT(mount->affected_by, AFF_CHARM); mount->mover = mount->m3; mount->m4 = ch->pcdata->hometown; /* This isn't needed anymore since you can order your pets --Shaddai xSET_BIT(pet->affected_by, AFF_CHARM); */ argument = one_argument(argument, arg); if (arg[0] != '\0') { sprintf(buf, "%s %s", mount->name, arg); STRFREE(mount->name); mount->name = STRALLOC(buf); } sprintf(buf, "%sA neck tag says 'I am a mount, don't kill me'.\n\r", mount->description); STRFREE(mount->description); mount->description = STRALLOC(buf); char_to_room(mount, ch->in_room); add_follower(mount, ch); send_to_char("Enjoy your mount.\n\r", ch); act(AT_ACTION, "$n bought $N as a mount.", ch, NULL, mount, TO_ROOM); return; } else { CHAR_DATA *keeper; OBJ_DATA *obj; OBJ_DATA *fobj; AREA_DATA *pArea; /* Passing resets to special mobs */ ROOM_INDEX_DATA *pRoom; int cost; int noi = 1; /* Number of items */ sh_int mnoi = 20; /* Max number of items to be bought at once */ if ((keeper = find_keeper(ch)) == NULL) return; pRoom = keeper->in_room; pArea = pRoom->area; maxgold = 5000000; 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->reply = 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->reply = keeper; return; } if (!IS_OBJ_STAT(obj, ITEM_INVENTORY) && (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->reply = keeper; return; } if (IS_UNIQUE(ch, obj)) { act(AT_TELL, "$n tells you 'You can only have 1 of those items on you at a time!", keeper, NULL, ch, TO_VICT); ch->reply = keeper; return; } if (ch->race == RACE_HOBBIT) { cost = cost * 85 / 100; if (cost < obj->cost) cost = obj->cost; } if (!IS_NPC(ch) && LEARNED(ch, gsn_haggling) > 0) { level = POINT_LEVEL(LEARNED(ch, gsn_haggling), MASTERED(ch, gsn_haggling)); cost = cost * (100-(level/2)) / 100; //Cannot go below actual cost of the item if (cost < obj->cost) cost = obj->cost; if (MASTERED(ch, gsn_haggling) == 4 && cost > obj->cost) cost = obj->cost; } if (ch->in_room->area->kingdom > 1) { tax = kingdom_table[ch->in_room->area->kingdom]->salestax; taxk = ch->in_room->area->salestax; } else { tax = 0; taxk = 0; } ctax = (cost * tax) / 1000; taxk = (cost * taxk) / 1000; if (ch->gold < (cost + ctax + taxk)) { act(AT_TELL, "$n tells you 'You can't afford to buy $p.'", keeper, obj, ch, TO_VICT); ch->reply = keeper; return; } if (obj->level > ch->level) { act(AT_TELL, "$n tells you 'You can't use $p yet.'", keeper, obj, ch, TO_VICT); ch->reply = keeper; return; } if (IS_OBJ_STAT(obj, ITEM_PROTOTYPE) && get_trust(ch) < 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->reply = keeper; return; } if (get_ch_carry_number(ch) + get_obj_number(obj) > can_carry_n(ch)) { send_to_char("You can't carry that many items.\n\r", ch); return; } if (get_ch_carry_weight(ch) + (get_obj_weight(obj) * noi) + (noi > 1 ? 2 : 0) > can_carry_w(ch)) { send_to_char("You can't carry that much weight.\n\r", ch); return; } if (!IS_NPC(ch) && LEARNED(ch, gsn_haggling) > 0) learn_from_success(ch, gsn_haggling, NULL); 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 { sprintf(arg, "$n buys %d $p%s.", noi, (obj->short_descr[strlen(obj->short_descr) - 1] == 's' ? "" : "s")); act(AT_ACTION, arg, ch, obj, NULL, TO_ROOM); sprintf(arg, "You buy %d $p%s.", noi, (obj->short_descr[strlen(obj->short_descr) - 1] == 's' ? "" : "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); } if (ch->pcdata->keeper == keeper->pIndexData->vnum) { cost = 0; } ch->gold -= (cost + ctax + taxk); keeper->gold += cost; if (IN_WILDERNESS(ch)) { if ((town = find_town(ch->coord->x, ch->coord->y, ch->map)) != NULL) { if (tax) { if ((dtown = find_town(ch->coord->x, ch->coord->y, ch->map)) != NULL) { if ((get_current_hold(dtown) + (ctax/100)) <= dtown->hold) dtown->coins += ctax; } } if (taxk) { if ((get_current_hold(town) + (taxk/100)) <= town->hold) town->coins += taxk; } } } if (xIS_SET(keeper->act, ACT_CASTEMOB)) keeper->pIndexData->gold += cost; if (!xIS_SET(keeper->act, ACT_CASTEMOB)) { if (keeper->gold > maxgold) { boost_economy(keeper->in_room->area, keeper->gold - maxgold / 2); keeper->gold = maxgold / 2; act(AT_ACTION, "$n puts some gold into a large safe.", keeper, NULL, NULL, TO_ROOM); } } if (IS_OBJ_STAT(obj, ITEM_INVENTORY)) { OBJ_DATA *buy_obj, *bag; SLAB_DATA *slab; int race; buy_obj = create_object(obj->pIndexData, obj->level); if (obj->value[6] > 99 && (obj->item_type == ITEM_WEAPON || obj->item_type == ITEM_ARMOR) && xIS_SET(obj->extra_flags, ITEM_FORGEABLE)) { for (slab = first_slab; slab; slab = slab->next) { if (slab->vnum == obj->value[6]) break; } if (!slab) { bug("Do_Buy, Obj %d on Mob %d has an invalid slab.", obj->pIndexData->vnum, keeper->pIndexData->vnum); } else { race = keeper->race; if (keeper->race < 0 || keeper->race >= MAX_RACE) keeper->race = 0; //Needs a valid race alter_forge_obj(keeper, buy_obj, create_object(get_obj_index(slab->vnum), 1), slab); keeper->race = race; } } /* * 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(get_obj_index(OBJ_VNUM_SHOPPING_BAG), 1); xSET_BIT(bag->extra_flags, ITEM_GROUNDROT); //bag->timer = 10; /* Blodkai, 4/97 */ /* perfect size bag ;) */ bag->value[0] = bag->weight + (buy_obj->weight * noi); buy_obj->count = noi; obj->pIndexData->count += (noi - 1); numobjsloaded += (noi - 1); obj_to_obj(buy_obj, bag); obj_to_char(bag, ch); } else obj_to_char(buy_obj, ch); } else { if (xIS_SET(keeper->act, ACT_CASTEMOB)) { fobj = shop_oclean(keeper, obj); fobj->level = 1; obj_from_char(obj); obj_to_char(fobj, ch); delete_obj(obj->pIndexData); kupkeep(pArea, pRoom); fdarea(keeper, pArea->filename); } 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(CHAR_DATA * ch, char *argument) { /* Constants for producing the flags */ char *divleft = "-----------------------------------[ "; char *divright = " ]-----------------------------------"; int cost; int level; if (xIS_SET(ch->in_room->room_flags, ROOM_MOUNT_SHOP)) { ROOM_INDEX_DATA *pRoomIndexNext; CHAR_DATA *mount; bool found; pRoomIndexNext = get_room_index(ch->in_room->vnum + 1); if (!pRoomIndexNext) { bug("Do_list: bad mount shop at vnum %d.", ch->in_room->vnum); send_to_char("You can't do that here.\n\r", ch); return; } found = FALSE; for (mount = pRoomIndexNext->first_person; mount; mount = mount->next_in_room) { if (xIS_SET(mount->act, ACT_MOUNTSAVE) && IS_NPC(mount)) { if (!found) { found = TRUE; send_to_pager("Mounts for sale:\n\r", ch); send_to_pager("Endurance Armor HP MaxWeight Cost Name\n\r", ch); send_to_pager("----------------------------------------------------------------\n\r", ch); } cost = mount->m2; if (ch->race == RACE_HOBBIT) { cost = cost * 85 / 100; } if (!IS_NPC(ch) && LEARNED(ch, gsn_haggling) > 0) { level = POINT_LEVEL(LEARNED(ch, gsn_haggling), MASTERED(ch, gsn_haggling)); cost = cost * (100-(level/2)) / 100; } pager_printf(ch, "%s[%2d] [%2d] [%3d] [%4d] %8d %s\n\r", char_color_str(AT_PERSON, ch), mount->m3, mount->armor, mount->max_hit, can_carry_w(mount), mount->m2, mount->short_descr); } } if (!found) send_to_char("Sorry, we're out of mounts right now.\n\r", ch); return; } else { char arg[MIL]; char *rest; CHAR_DATA *keeper; OBJ_DATA *obj; bool found; /* bool listall; */ int lower, upper; rest = one_argument(argument, arg); if ((keeper = find_keeper(ch)) == NULL) return; found = FALSE; lower = -2; 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; 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 */ for (obj = keeper->first_carrying; obj; obj = obj->next_content) { if (obj->wear_loc == WEAR_NONE && can_see_obj(ch, obj) && (cost = get_cost(ch, keeper, obj, 2)) > 0 && (arg[0] == '\0' || nifty_is_name(arg, obj->name))) { if (!found) { found = TRUE; send_to_pager("&c&w[Lv Price] Item\n\r---------------\n\r", ch); } if (obj->level <= upper) { pager_printf(ch, "%s%2d%s\n\r", divleft, upper, divright); upper = -1; } if (obj->level < lower) { pager_printf(ch, "%s%2d%s\n\r", divleft, lower, divright); lower = -1; } if (ch->race == RACE_HOBBIT) { cost = cost * 85 / 100; if (cost < obj->cost) cost = obj->cost; } if (!IS_NPC(ch) && LEARNED(ch, gsn_haggling) > 0) { level = POINT_LEVEL(LEARNED(ch, gsn_haggling), MASTERED(ch, gsn_haggling)); cost = cost * (100-(level/2)) / 100; //Cannot go below actual cost of the item if (cost < obj->cost) cost = obj->cost; if (MASTERED(ch, gsn_haggling) == 4 && cost > obj->cost) cost = obj->cost; } pager_printf( ch, "[%2d %5d] "MXPTAG ("list '%s' '%s'")"%s"MXPTAG ("/list") ".\n\r",obj->level, cost, obj->name, obj->short_descr, capitalize( obj->short_descr ) ); } } if (lower >= 0) { pager_printf(ch, "%s%2d%s\n\r", divleft, lower, divright); } if (!found) { if (arg[0] == '\0') send_to_char("You can't buy anything here.\n\r", ch); else send_to_char("You can't buy that here.\n\r", ch); } return; } } void do_sell(CHAR_DATA * ch, char *argument) { AREA_DATA *pArea; /* Passing resets to special mobs */ ROOM_INDEX_DATA *pRoom; char buf[MSL]; char arg[MIL]; CHAR_DATA *keeper; OBJ_DATA *obj; OBJ_DATA *iobj; OBJ_DATA *fobj; int cost; int outcome = 0; int objcount = 0; int maxaobj = 0; int level; one_argument(argument, arg); if (arg[0] == '\0') { send_to_char("Sell what?\n\r", ch); return; } if ((keeper = find_keeper(ch)) == NULL) 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->reply = keeper; return; } if (!can_drop_obj(ch, obj)) { send_to_char("You can't let go of it!\n\r", ch); return; } /* Prevents giving of special items (rare items) -- Xerves 3/24/98*/ if (IS_OBJ_STAT(obj, ITEM_NOGIVE)) { send_to_char("Xerves should personally smack you for trying to find a loophole. Cannot sell this item.\n\r", ch); 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 (ch->race == RACE_HOBBIT) { cost = cost * 115 / 100; if (cost > obj->cost) cost = obj->cost; } if (!IS_NPC(ch) && LEARNED(ch, gsn_swindling) > 0) { level = POINT_LEVEL(LEARNED(ch, gsn_swindling), MASTERED(ch, gsn_swindling)); cost = cost * (100+(level/2)) / 100; //Cannot go above actual cost of the item if (cost > obj->cost) cost = obj->cost; if (MASTERED(ch, gsn_swindling) == 4 && cost < obj->cost) cost = obj->cost; learn_from_success(ch, gsn_swindling, NULL); } if (xIS_SET(keeper->act, ACT_CASTEMOB)) if ((keeper->pIndexData->m1 != 0) && (keeper->pIndexData->m2 != 0) && (keeper->pIndexData->m3 != 0) && (keeper->pIndexData->m4 != 0) && (keeper->pIndexData->m5 != 0)) { outcome = keeper->gold - cost; if (outcome < keeper->m3) { act(AT_TELL, "$n tells you, 'I cannot afford to sell you $p, sorry'", keeper, obj, ch, TO_VICT); return; } if (obj->cost < keeper->m1 || obj->cost > keeper->m2) { sprintf(buf, "$n tells you, '$p is not worth %d to %d gold'", keeper->m1, keeper->m2); act(AT_TELL, buf, keeper, obj, ch, TO_VICT); return; } } if (xIS_SET(keeper->act, ACT_CASTEMOB)) { if (keeper->pIndexData->m6 == 0) maxaobj = 20; else maxaobj = keeper->pIndexData->m6; for (iobj = keeper->first_carrying; iobj; iobj = iobj->next_content) { if (iobj->wear_loc == WEAR_NONE) objcount++; } if (objcount + 1 > maxaobj) { sprintf(buf, "$n tells you, '$p exceeds my limit of %d items.'", maxaobj); act(AT_TELL, buf, keeper, obj, ch, TO_VICT); return; } } if (cost >= keeper->gold) { 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); if (ch->pcdata->keeper == keeper->pIndexData->vnum) { cost = 0; } ch->gold += cost; keeper->gold -= cost; if (xIS_SET(keeper->act, ACT_CASTEMOB)) keeper->pIndexData->gold -= cost; if (keeper->gold < 0) keeper->gold = 0; pRoom = keeper->in_room; pArea = pRoom->area; if (obj->item_type == ITEM_TRASH) { extract_obj(obj); if (xIS_SET(keeper->act, ACT_CASTEMOB)) kupkeep(pArea, pRoom); } else { if (xIS_SET(keeper->act, ACT_CASTEMOB)) { fobj = shop_ocreate(keeper, obj); obj_from_char(obj); extract_obj(obj); obj_to_char(fobj, keeper); kupkeep(pArea, pRoom); fdarea(keeper, pArea->filename); } else { obj_from_char(obj); obj_to_char(obj, keeper); } } return; } void do_value(CHAR_DATA * ch, char *argument) { char buf[MSL]; CHAR_DATA *keeper; OBJ_DATA *obj; int level; int cost; if (argument[0] == '\0') { send_to_char("Value what?\n\r", ch); return; } if ((keeper = find_keeper(ch)) == NULL) 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->reply = keeper; return; } if (!can_drop_obj(ch, obj)) { send_to_char("You can't let go of it!\n\r", ch); 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 (ch->race == RACE_HOBBIT) { cost = cost * 115 / 100; if (cost > obj->cost) cost = obj->cost; } if (!IS_NPC(ch) && LEARNED(ch, gsn_swindling) > 0) { level = POINT_LEVEL(LEARNED(ch, gsn_swindling), MASTERED(ch, gsn_swindling)); cost = cost * (100+(level/2)) / 100; //Cannot go above actual cost of the item if (cost > obj->cost) cost = obj->cost; if (MASTERED(ch, gsn_swindling) == 4 && cost < obj->cost) cost = obj->cost; } 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->reply = keeper; return; } /* * Repair a single object. Used when handling "repair all" - Gorog */ void repair_one_obj(CHAR_DATA * ch, CHAR_DATA * keeper, OBJ_DATA * obj, char *arg, int maxgold, char *fixstr, char *fixstr2) { char buf[MSL]; char arg1[MIL]; int cost = 0; int level; if (obj->item_type == ITEM_WEAPON && (obj->value[4] > 0 || obj->value[5] > 0)) { act(AT_TELL, "$n tells you, 'Sorry, I cannot repair $p because a great magical power prevents me.'", keeper, obj, ch, TO_VICT); return; } if (!can_drop_obj(ch, obj)) ch_printf(ch, "You can't let go of %s.\n\r", obj->name); 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->gold) { if (ch->race == RACE_HOBBIT) { cost = cost * 85 / 100; } if (!IS_NPC(ch) && LEARNED(ch, gsn_haggling) > 0) { level = POINT_LEVEL(LEARNED(ch, gsn_haggling), MASTERED(ch, gsn_haggling)); cost = cost * (100-(level/2)) / 100; } sprintf(buf, "$N tells you, 'It will cost %d piece%s of gold to %s %s...'", cost, cost == 1 ? "" : "s", fixstr, obj->name); 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 { if (ch->race == RACE_HOBBIT) { cost = cost * 85 / 100; } if (!IS_NPC(ch) && LEARNED(ch, gsn_haggling) > 0) { level = POINT_LEVEL(LEARNED(ch, gsn_haggling), MASTERED(ch, gsn_haggling)); cost = cost * (100-(level/2)) / 100; } one_argument(arg, arg1); if (!str_cmp(arg1, "cost")) { sprintf(buf, "$N informs you it will cost %d to fix $p.", cost); act(AT_ACTION, buf, ch, obj, keeper, TO_CHAR); return; } if (!IS_NPC(ch) && LEARNED(ch, gsn_haggling) > 0) learn_from_success(ch, gsn_haggling, NULL); 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->gold -= cost; keeper->gold += cost; if (keeper->gold < 0) keeper->gold = 0; else if (keeper->gold > maxgold) { boost_economy(keeper->in_room->area, keeper->gold - maxgold / 2); keeper->gold = maxgold / 2; act(AT_ACTION, "$n puts some gold into a large safe.", keeper, NULL, NULL, TO_ROOM); } switch (obj->item_type) { default: send_to_char("For some reason, you think you got ripped off...\n\r", ch); break; case ITEM_ARMOR: if (IS_SET(obj->wear_flags, ITEM_WEAR_SHIELD)) { obj->value[0] = obj->value[1]; } else obj->value[3] = INIT_ARMOR_CONDITION; break; case ITEM_WEAPON: obj->value[0] = INIT_ARMOR_CONDITION; break; case ITEM_SHEATH: obj->value[3] = INIT_ARMOR_CONDITION; } oprog_repair_trigger(ch, obj); } } void do_break(CHAR_DATA *ch, char *argument) { int scnt; OBJ_DATA *first_obj, *fobj; SLAB_DATA *slab; FORGE_DATA *forge; char arg[MIL]; int race; int slabs; char *wbuf; char wname[MIL]; //for stripping to check race OBJ_DATA *repair; int chance; argument = one_argument(argument, arg); for(first_obj = ch->first_carrying; first_obj; first_obj = first_obj->next_content) { if( is_name(arg, first_obj->name) && xIS_SET(first_obj->extra_flags, ITEM_FORGEABLE) && first_obj->wear_loc == WEAR_NONE ) break; } if (!first_obj) { for(first_obj = ch->in_room->first_content; first_obj; first_obj = first_obj->next_content) { if( is_name(arg, first_obj->name) && xIS_SET(first_obj->extra_flags, ITEM_FORGEABLE) && first_obj->wear_loc == WEAR_NONE ) break; } } if (!first_obj) { send_to_char("That item is either not in your inventory or on the ground.\n\r", ch); return; } if (first_obj->item_type == ITEM_PROJECTILE) { send_to_char("You cannot break down arrows.\n\r", ch); return; } if (IS_OBJ_STAT(first_obj, ITEM_KINGDOMEQ)) { send_to_char("Cannot break this item, it is kingdom eq\n\r", ch); return; } for(slab = first_slab; slab; slab = slab->next) { if(is_name(slab->adj, first_obj->name) ) break; } if (!slab) { send_to_char("Error: Did not find the Ore, tell an immortal.\n\r", ch); bug("forge: Forgeable has an invalid ore."); return; } for (forge = first_forge; forge; forge = forge->next) { if (forge->vnum == first_obj->pIndexData->vnum) break; } if (!forge) { send_to_char("Error: Error with the weapon/armor, tell an immotal.\n\r", ch); bug("Forge: Could not find the weapon/armor in the forge list"); return; } for (repair = ch->first_carrying; repair; repair = repair->next_content) { if (repair->item_type == ITEM_REPAIR) break; } if (!repair) { send_to_char("You do not have a hammer in which to break with.\n\r", ch); return; } separate_obj(first_obj); separate_obj(repair); wbuf = first_obj->name; wbuf = one_argument(wbuf, wname); wbuf = one_argument(wbuf, wname); wname[0] = UPPER(wname[0]); if (!str_prefix(wname, "Fairy")) race = 5; else if (!str_prefix(wname, "Hobbit")) race = 4; else if (!str_prefix(wname, "Ogre")) race = 3; else if (!str_prefix(wname, "Dwarven")) race = 2; else if (!str_prefix(wname, "Elven")) race = 1; else if (!str_prefix(wname, "Human")) race = 0; else { bug("Invalid Race Name %s, on player %s", wname, ch->name); send_to_char("Error: Invalid Race Name, tell an immortal.\n\r", ch); return; } if (race == 5) //Fairy slabs = forge->slabnum * 4 / 10; else if (race == 4) //Hobbit slabs = forge->slabnum * 6 / 10; else if (race == 1) //Elf slabs = forge->slabnum * 85 / 100; else if (race == 2) //Dwarf slabs = forge->slabnum * 12 / 10; else if (race == 3) //Ogre slabs = forge->slabnum * 15 / 10; else //Human slabs = forge->slabnum; if (ch->race == RACE_DWARF) slabs = slabs * number_range(58, 63) / 100; else slabs = slabs * number_range(40, 53) / 100; if (slabs < 1) slabs = 1; chance = 70; if (ch->race == RACE_DWARF) chance = 95; if (number_range(1, 100) <= chance) { for (scnt = 0; scnt < slabs; scnt++) { fobj = create_object(get_obj_index(slab->vnum), 1); obj_to_room(fobj, ch->in_room, ch); } ch_printf(ch, "You pull out your handy repair hammer and begin to beat the hell out of %s.\n\r", first_obj->short_descr); ch_printf(ch, "You get lucky and successfully split it into %d slabs.\n\r", slabs); extract_obj(first_obj); chance = 20; if (ch->race == RACE_DWARF) chance = 5; if (number_range(1, 100) <= chance) { act(AT_RED, "$p starts to show some wear after its use.", ch, repair, NULL, TO_CHAR); if (--repair->value[0] <= 0) { act(AT_RED, "With the last strike, $p breaks and becomes useless.", ch, repair, NULL, TO_CHAR); separate_obj(repair); extract_obj(repair); } } return; } else { ch_printf(ch, "You pull out your handy repair hammer and begin to beat the hell out of %s.\n\r", first_obj->short_descr); ch_printf(ch, "However, the only thing you get is a broken, useless %s.\n\r", first_obj->short_descr); extract_obj(first_obj); if (number_range(1, 100) <= 20) { act(AT_RED, "$p starts to show some wear after its use.", ch, repair, NULL, TO_CHAR); if (--repair->value[0] <= 0) { act(AT_RED, "With the last strike, $p breaks and becomes useless.", ch, repair, NULL, TO_CHAR); separate_obj(repair); extract_obj(repair); } } } } void do_fix(CHAR_DATA *ch, char *argument) { OBJ_DATA *obj; OBJ_DATA *repair; int points; char arg[MIL]; if (argument[0] == '\0') { send_to_char("Syntax: fix <item needing repaired> <item which to do the repairing>\n\r", ch); return; } argument = one_argument(argument, arg); if ((obj = get_obj_carry(ch, arg)) == NULL) { if ((obj= get_obj_wear(ch, arg)) == NULL) { send_to_char("The item you are looking for is not in your inventory or being wielded.\n\r", ch); return; } } if (obj->item_type != ITEM_ARMOR && obj->item_type != ITEM_WEAPON && obj->item_type != ITEM_SHEATH) { send_to_char("You can only fix armor, weapons, and sheaths.\n\r", ch); return; } for (repair = ch->first_carrying; repair; repair = repair->next_content) { if (repair->item_type == ITEM_REPAIR) break; } if (!repair) { send_to_char("You do not have a hammer in which to repair with.\n\r", ch); return; } if (obj->item_type == ITEM_WEAPON && (obj->value[4] > 0 || obj->value[5] > 0)) { send_to_char("There is a magical property to this weapon preventing normal repairs.\n\r", ch); return; } if (obj->item_type == ITEM_WEAPON) { if (obj->value[0] == INIT_ARMOR_CONDITION) { send_to_char("That item is fully repaired!\n\r", ch); return; } } if (obj->item_type == ITEM_ARMOR && !IS_SET(obj->wear_flags, ITEM_WEAR_SHIELD)) { if (obj->value[3] == INIT_ARMOR_CONDITION) { send_to_char("That item is fully repaired!\n\r", ch); return; } } if (obj->item_type == ITEM_ARMOR && IS_SET(obj->wear_flags, ITEM_WEAR_SHIELD)) { if (obj->value[0] == obj->value[1]) { send_to_char("That item is fully repaired!\n\r", ch); return; } } if (obj->item_type == ITEM_SHEATH) { if (obj->value[3] == INIT_ARMOR_CONDITION) { send_to_char("That item is fully repaired!\n\r", ch); return; } } points = POINT_LEVEL(GET_POINTS(ch, gsn_repair, 0, 1), GET_MASTERY(ch, gsn_repair, 0, 1)); separate_obj(obj); separate_obj(repair); if (ch->race == RACE_DWARF) points += 60; if (number_range(1, 100) <= UMIN(95, repair->value[2] + (points / 3))) { int fixed = 0; int repairv = number_range(70*repair->value[3], 130*repair->value[3]); repairv = repairv / 100; repairv = repairv+points/2; if (obj->item_type == ITEM_WEAPON) { obj->value[0] += UMAX(1, repairv); if (obj->value[0] >= INIT_ARMOR_CONDITION) { obj->value[0] = INIT_ARMOR_CONDITION; fixed = 1; } } if (obj->item_type == ITEM_ARMOR && !IS_SET(obj->wear_flags, ITEM_WEAR_SHIELD)) { obj->value[3] += UMAX(1, repairv); if (obj->value[3] >= INIT_ARMOR_CONDITION) { obj->value[3] = INIT_ARMOR_CONDITION; fixed = 1; } } if (obj->item_type == ITEM_ARMOR && IS_SET(obj->wear_flags, ITEM_WEAR_SHIELD)) { obj->value[0] += UMAX(1, repairv * obj->value[1] / 1000); if (obj->value[0] >= obj->value[1]) { obj->value[0] = obj->value[1]; fixed = 1; } } if (obj->item_type == ITEM_SHEATH) { obj->value[3] += UMAX(1, repairv); if (obj->value[3] >= INIT_ARMOR_CONDITION) { obj->value[3] = INIT_ARMOR_CONDITION; fixed = 1; } } if (fixed == 1) act(AT_GREEN, "You successfully repair $p to its perfect form.", ch, obj, NULL, TO_CHAR); else act(AT_GREEN, "You successfully repair $p.", ch, obj, NULL, TO_CHAR); learn_from_success(ch, gsn_repair, NULL); } else { act(AT_DGREEN, "You fail to repair $p,", ch, obj, NULL, TO_CHAR); learn_from_failure(ch, gsn_repair, NULL); } points = POINT_LEVEL(GET_POINTS(ch, gsn_repair, 0, 1), GET_MASTERY(ch, gsn_repair, 0, 1)); if (ch->race == RACE_DWARF) points += 60; points = 60+(points/3); points += URANGE(7, get_curr_lck(ch)-14, -5); points = URANGE(60, points, 95); if (number_range(1,100) > points) { act(AT_RED, "$p starts to show some wear after its use.", ch, repair, NULL, TO_CHAR); if (--repair->value[0] <= 0) { act(AT_RED, "With the last strike, $p breaks and becomes useless.", ch, repair, NULL, TO_CHAR); extract_obj(repair); } } return; } void do_repair(CHAR_DATA * ch, char *argument) { CHAR_DATA *keeper; OBJ_DATA *obj; char *fixstr; char arg1[MSL]; char arg2[MSL]; char *arg2p = arg2; char *fixstr2; int maxgold; if (argument[0] == '\0') { send_to_char("Repair what?\n\r", ch); return; } if ((keeper = find_fixer(ch)) == NULL) return; maxgold = 10000000; switch (keeper->pIndexData->rShop->shop_type) { default: case SHOP_FIX: fixstr = "repair"; fixstr2 = "repairs"; break; case SHOP_RECHARGE: fixstr = "recharge"; fixstr2 = "recharges"; break; } if (!strcmp(argument, "all")) { for (obj = ch->first_carrying; obj; obj = obj->next_content) { if (obj->wear_loc == WEAR_NONE && can_see_obj(ch, obj) && can_see_obj(keeper, obj) && (obj->item_type == ITEM_ARMOR || obj->item_type == ITEM_WEAPON || obj->item_type == ITEM_SHEATH)) repair_one_obj(ch, keeper, obj, argument, maxgold, fixstr, fixstr2); } return; } one_argument(argument, arg1); if (!str_cmp(arg1, "cost")) arg2p = one_argument(argument, arg1); else arg2p = argument; if ((obj = get_obj_carry(ch, arg2p)) == NULL) { act(AT_TELL, "$n tells you 'You don't have that item.'", keeper, NULL, ch, TO_VICT); ch->reply = keeper; return; } repair_one_obj(ch, keeper, obj, argument, maxgold, fixstr, fixstr2); } void appraise_all(CHAR_DATA * ch, CHAR_DATA * keeper, char *fixstr) { OBJ_DATA *obj; char buf[MSL], *pbuf = buf; int cost = 0, total = 0; for (obj = ch->first_carrying; obj != NULL; obj = obj->next_content) { if (obj->wear_loc == WEAR_NONE && can_see_obj(ch, obj) && (obj->item_type == ITEM_ARMOR || obj->item_type == ITEM_WEAPON)) { if (!can_drop_obj(ch, obj)) ch_printf(ch, "You can't let go of %s.\n\r", obj->name); 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->name); act(AT_TELL, buf, ch, NULL, keeper, TO_CHAR); total += cost; } } } if (total > 0) { send_to_char("\n\r", ch); 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(pbuf, "$N tells you, 'Remember there is a 10% surcharge for repair all.'"); act(AT_TELL, buf, ch, NULL, keeper, TO_CHAR); } } void do_appraise(CHAR_DATA * ch, char *argument) { char buf[MSL]; char arg[MIL]; CHAR_DATA *keeper; OBJ_DATA *obj; int cost; char *fixstr; int level; one_argument(argument, arg); if (arg[0] == '\0') { send_to_char("Appraise what?\n\r", ch); return; } if ((keeper = find_fixer(ch)) == NULL) return; switch (keeper->pIndexData->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->reply = keeper; return; } if (!can_drop_obj(ch, obj)) { send_to_char("You can't let go of it.\n\r", ch); 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; } if (ch->race == RACE_HOBBIT) { cost = cost * 85 / 100; } if (!IS_NPC(ch) && LEARNED(ch, gsn_haggling) > 0) { level = POINT_LEVEL(LEARNED(ch, gsn_haggling), MASTERED(ch, gsn_haggling)); cost = cost * (100-(level/2)) / 100; } 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->gold) 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(CHAR_DATA * ch, char *argument) { SHOP_DATA *shop; sh_int vnum; MOB_INDEX_DATA *mob; if (!argument || argument[0] == '\0') { send_to_char("Usage: makeshop <mobvnum>\n\r", ch); return; } vnum = atoi(argument); if ((mob = get_mob_index(vnum)) == NULL) { send_to_char("Mobile not found.\n\r", ch); return; } if (!can_medit(ch, mob)) return; if (mob->pShop) { send_to_char("This mobile already has a shop.\n\r", ch); return; } CREATE(shop, SHOP_DATA, 1); LINK(shop, first_shop, last_shop, next, prev); shop->keeper = vnum; shop->profit_buy = 120; shop->profit_sell = 90; shop->open_hour = 0; shop->close_hour = 23; mob->pShop = shop; send_to_char("Done.\n\r", ch); return; } void do_shopset(CHAR_DATA * ch, char *argument) { SHOP_DATA *shop; MOB_INDEX_DATA *mob, *mob2; char arg1[MIL]; char arg2[MIL]; sh_int vnum; int value; argument = one_argument(argument, arg1); argument = one_argument(argument, arg2); if (arg1[0] == '\0' || arg2[0] == '\0') { send_to_char("Usage: shopset <mob vnum> <field> value\n\r", ch); send_to_char("\n\rField being one of:\n\r", ch); send_to_char(" buy0 buy1 buy2 buy3 buy4 buy sell open close keeper\n\r", ch); return; } vnum = atoi(arg1); if ((mob = get_mob_index(vnum)) == NULL) { send_to_char("Mobile not found.\n\r", ch); return; } if (!can_medit(ch, mob)) return; if (!mob->pShop) { send_to_char("This mobile doesn't keep a shop.\n\r", ch); 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) { send_to_char("Invalid item type!\n\r", ch); return; } shop->buy_type[0] = value; send_to_char("Done.\n\r", ch); return; } if (!str_cmp(arg2, "buy1")) { if (!is_number(argument)) value = get_otype(argument); if (value < 0 || value > MAX_ITEM_TYPE) { send_to_char("Invalid item type!\n\r", ch); return; } shop->buy_type[1] = value; send_to_char("Done.\n\r", ch); return; } if (!str_cmp(arg2, "buy2")) { if (!is_number(argument)) value = get_otype(argument); if (value < 0 || value > MAX_ITEM_TYPE) { send_to_char("Invalid item type!\n\r", ch); return; } shop->buy_type[2] = value; send_to_char("Done.\n\r", ch); return; } if (!str_cmp(arg2, "buy3")) { if (!is_number(argument)) value = get_otype(argument); if (value < 0 || value > MAX_ITEM_TYPE) { send_to_char("Invalid item type!\n\r", ch); return; } shop->buy_type[3] = value; send_to_char("Done.\n\r", ch); return; } if (!str_cmp(arg2, "buy4")) { if (!is_number(argument)) value = get_otype(argument); if (value < 0 || value > MAX_ITEM_TYPE) { send_to_char("Invalid item type!\n\r", ch); return; } shop->buy_type[4] = value; send_to_char("Done.\n\r", ch); return; } if (!str_cmp(arg2, "buy")) { if (value <= (shop->profit_sell + 5) || value > 1000) { send_to_char("Out of range.\n\r", ch); return; } shop->profit_buy = value; send_to_char("Done.\n\r", ch); return; } if (!str_cmp(arg2, "sell")) { if (value < 0 || value >= (shop->profit_buy - 5)) { send_to_char("Out of range.\n\r", ch); return; } shop->profit_sell = value; send_to_char("Done.\n\r", ch); return; } if (!str_cmp(arg2, "open")) { if (value < 0 || value > 23) { send_to_char("Out of range.\n\r", ch); return; } shop->open_hour = value; send_to_char("Done.\n\r", ch); return; } if (!str_cmp(arg2, "close")) { if (value < 0 || value > 23) { send_to_char("Out of range.\n\r", ch); return; } shop->close_hour = value; send_to_char("Done.\n\r", ch); return; } if (!str_cmp(arg2, "keeper")) { if ((mob2 = get_mob_index(vnum)) == NULL) { send_to_char("Mobile not found.\n\r", ch); return; } if (!can_medit(ch, mob)) return; if (mob2->pShop) { send_to_char("That mobile already has a shop.\n\r", ch); return; } mob->pShop = NULL; mob2->pShop = shop; shop->keeper = value; send_to_char("Done.\n\r", ch); return; } do_shopset(ch, ""); return; } void do_shopstat(CHAR_DATA * ch, char *argument) { SHOP_DATA *shop; MOB_INDEX_DATA *mob; sh_int vnum; if (argument[0] == '\0') { send_to_char("Usage: shopstat <keeper vnum>\n\r", ch); return; } vnum = atoi(argument); if ((mob = get_mob_index(vnum)) == NULL) { send_to_char("Mobile not found.\n\r", ch); return; } if (!mob->pShop) { send_to_char("This mobile doesn't keep a shop.\n\r", ch); return; } shop = mob->pShop; ch_printf(ch, "Keeper: %d %s\n\r", shop->keeper, mob->short_descr); ch_printf(ch, "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_printf(ch, "Profit: buy %3d%% sell %3d%%\n\r", shop->profit_buy, shop->profit_sell); ch_printf(ch, "Hours: open %2d close %2d\n\r", shop->open_hour, shop->close_hour); return; } void do_shops(CHAR_DATA * ch, char *argument) { SHOP_DATA *shop; if (!first_shop) { send_to_char("There are no shops.\n\r", ch); return; } set_char_color(AT_NOTE, ch); for (shop = first_shop; shop; shop = shop->next) ch_printf(ch, "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(CHAR_DATA * ch, char *argument) { REPAIR_DATA *repair; sh_int vnum; MOB_INDEX_DATA *mob; if (!argument || argument[0] == '\0') { send_to_char("Usage: makerepair <mobvnum>\n\r", ch); return; } vnum = atoi(argument); if ((mob = get_mob_index(vnum)) == NULL) { send_to_char("Mobile not found.\n\r", ch); return; } if (!can_medit(ch, mob)) return; if (mob->rShop) { send_to_char("This mobile already has a repair shop.\n\r", ch); return; } CREATE(repair, REPAIR_DATA, 1); LINK(repair, first_repair, last_repair, next, prev); repair->keeper = vnum; repair->profit_fix = 100; repair->shop_type = SHOP_FIX; repair->open_hour = 0; repair->close_hour = 23; mob->rShop = repair; send_to_char("Done.\n\r", ch); return; } void do_repairset(CHAR_DATA * ch, char *argument) { REPAIR_DATA *repair; MOB_INDEX_DATA *mob, *mob2; char arg1[MIL]; char arg2[MIL]; sh_int vnum; int value; argument = one_argument(argument, arg1); argument = one_argument(argument, arg2); if (arg1[0] == '\0' || arg2[0] == '\0') { send_to_char("Usage: repairset <mob vnum> <field> value\n\r", ch); send_to_char("\n\rField being one of:\n\r", ch); send_to_char(" fix0 fix1 fix2 profit type open close keeper\n\r", ch); return; } vnum = atoi(arg1); if ((mob = get_mob_index(vnum)) == NULL) { send_to_char("Mobile not found.\n\r", ch); return; } if (!can_medit(ch, mob)) return; if (!mob->rShop) { send_to_char("This mobile doesn't keep a repair shop.\n\r", ch); 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) { send_to_char("Invalid item type!\n\r", ch); return; } repair->fix_type[0] = value; send_to_char("Done.\n\r", ch); return; } if (!str_cmp(arg2, "fix1")) { if (!is_number(argument)) value = get_otype(argument); if (value < 0 || value > MAX_ITEM_TYPE) { send_to_char("Invalid item type!\n\r", ch); return; } repair->fix_type[1] = value; send_to_char("Done.\n\r", ch); return; } if (!str_cmp(arg2, "fix2")) { if (!is_number(argument)) value = get_otype(argument); if (value < 0 || value > MAX_ITEM_TYPE) { send_to_char("Invalid item type!\n\r", ch); return; } repair->fix_type[2] = value; send_to_char("Done.\n\r", ch); return; } if (!str_cmp(arg2, "profit")) { if (value < 1 || value > 1000) { send_to_char("Out of range.\n\r", ch); return; } repair->profit_fix = value; send_to_char("Done.\n\r", ch); return; } if (!str_cmp(arg2, "type")) { if (value < 1 || value > 2) { send_to_char("Out of range.\n\r", ch); return; } repair->shop_type = value; send_to_char("Done.\n\r", ch); return; } if (!str_cmp(arg2, "open")) { if (value < 0 || value > 23) { send_to_char("Out of range.\n\r", ch); return; } repair->open_hour = value; send_to_char("Done.\n\r", ch); return; } if (!str_cmp(arg2, "close")) { if (value < 0 || value > 23) { send_to_char("Out of range.\n\r", ch); return; } repair->close_hour = value; send_to_char("Done.\n\r", ch); return; } if (!str_cmp(arg2, "keeper")) { if ((mob2 = get_mob_index(vnum)) == NULL) { send_to_char("Mobile not found.\n\r", ch); return; } if (!can_medit(ch, mob)) return; if (mob2->rShop) { send_to_char("That mobile already has a repair shop.\n\r", ch); return; } mob->rShop = NULL; mob2->rShop = repair; repair->keeper = value; send_to_char("Done.\n\r", ch); return; } do_repairset(ch, ""); return; } void do_repairstat(CHAR_DATA * ch, char *argument) { REPAIR_DATA *repair; MOB_INDEX_DATA *mob; sh_int vnum; if (argument[0] == '\0') { send_to_char("Usage: repairstat <keeper vnum>\n\r", ch); return; } vnum = atoi(argument); if ((mob = get_mob_index(vnum)) == NULL) { send_to_char("Mobile not found.\n\r", ch); return; } if (!mob->rShop) { send_to_char("This mobile doesn't keep a repair shop.\n\r", ch); return; } repair = mob->rShop; ch_printf(ch, "Keeper: %d %s\n\r", repair->keeper, mob->short_descr); ch_printf(ch, "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_printf(ch, "Profit: %3d%% Type: %d\n\r", repair->profit_fix, repair->shop_type); ch_printf(ch, "Hours: open %2d close %2d\n\r", repair->open_hour, repair->close_hour); return; } void do_repairshops(CHAR_DATA * ch, char *argument) { REPAIR_DATA *repair; if (!first_repair) { send_to_char("There are no repair shops.\n\r", ch); return; } set_char_color(AT_NOTE, ch); for (repair = first_repair; repair; repair = repair->next) ch_printf(ch, "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; }