/**************************************************************************** * [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. * * ------------------------------------------------------------------------ * * Misc module for general commands: not skills or spells * **************************************************************************** * Note: Most of the stuff in here would go in act_obj.c, but act_obj was * * getting big. * ****************************************************************************/ #include <sys/types.h> #include <stdio.h> #include <string.h> #include <time.h> #include "mud.h" extern int top_exit; /* * Fill a container * Many enhancements added by Thoric (ie: filling non-drink containers) */ void do_fill(CHAR_DATA * ch, char *argument) { char arg1[MIL]; char arg2[MIL]; OBJ_DATA *obj; OBJ_DATA *source; sh_int dest_item, src_item1, src_item2, src_item3; int diff = 0; bool all = FALSE; argument = one_argument(argument, arg1); argument = one_argument(argument, arg2); /* munch optional words */ if ((!str_cmp(arg2, "from") || !str_cmp(arg2, "with")) && argument[0] != '\0') argument = one_argument(argument, arg2); if (arg1[0] == '\0') { send_to_char("Fill what?\n\r", ch); return; } if (ms_find_obj(ch)) return; if ((obj = get_obj_carry(ch, arg1)) == NULL) { send_to_char("You do not have that item.\n\r", ch); return; } else dest_item = obj->item_type; src_item1 = src_item2 = src_item3 = -1; switch (dest_item) { default: act(AT_ACTION, "$n tries to fill $p... (Don't ask me how)", ch, obj, NULL, TO_ROOM); send_to_char("You cannot fill that.\n\r", ch); return; /* place all fillable item types here */ case ITEM_DRINK_CON: src_item1 = ITEM_FOUNTAIN; src_item2 = ITEM_BLOOD; break; case ITEM_HERB_CON: src_item1 = ITEM_HERB; src_item2 = ITEM_HERB_CON; break; case ITEM_PIPE: src_item1 = ITEM_HERB; src_item2 = ITEM_HERB_CON; break; case ITEM_CONTAINER: src_item1 = ITEM_CONTAINER; src_item2 = ITEM_CORPSE_NPC; src_item3 = ITEM_CORPSE_PC; break; } if (dest_item == ITEM_CONTAINER) { if (IS_SET(obj->value[1], CONT_CLOSED)) { act(AT_PLAIN, "The $d is closed.", ch, NULL, obj->name, TO_CHAR); return; } if (get_real_obj_weight(obj) / obj->count >= obj->value[0]) { send_to_char("It's already full as it can be.\n\r", ch); return; } } else { diff = obj->value[0] - obj->value[1]; if (diff < 1 || obj->value[1] >= obj->value[0]) { send_to_char("It's already full as it can be.\n\r", ch); return; } } if (dest_item == ITEM_PIPE && IS_SET(obj->value[3], PIPE_FULLOFASH)) { send_to_char("It's full of ashes, and needs to be emptied first.\n\r", ch); return; } if (arg2[0] != '\0') { if (dest_item == ITEM_CONTAINER && (!str_cmp(arg2, "all") || !str_prefix("all.", arg2))) { all = TRUE; source = NULL; } else /* This used to let you fill a pipe from an object on the ground. Seems to me you should be holding whatever you want to fill a pipe with. It's nitpicking, but I needed to change it to get a mobprog to work right. Check out Lord Fitzgibbon if you're curious. -Narn */ if (dest_item == ITEM_PIPE) { if ((source = get_obj_carry(ch, arg2)) == NULL) { send_to_char("You don't have that item.\n\r", ch); return; } if (source->item_type != src_item1 && source->item_type != src_item2 && source->item_type != src_item3) { act(AT_PLAIN, "You cannot fill $p with $P!", ch, obj, source, TO_CHAR); return; } } else { if ((source = get_obj_here(ch, arg2)) == NULL) { send_to_char("You cannot find that item.\n\r", ch); return; } } } else source = NULL; if (!source && dest_item == ITEM_PIPE) { send_to_char("Fill it with what?\n\r", ch); return; } if (!source) { bool found = FALSE; OBJ_DATA *src_next; found = FALSE; separate_obj(obj); for (source = ch->in_room->first_content; source; source = src_next) { src_next = source->next_content; if (dest_item == ITEM_CONTAINER) { if (!CAN_WEAR(source, ITEM_TAKE) || IS_OBJ_STAT(source, ITEM_BURIED) || (IS_OBJ_STAT(source, ITEM_PROTOTYPE) && !can_take_proto(ch)) || IS_OBJ_STAT(source, ITEM_NOGIVE) || get_ch_carry_weight(ch) + get_obj_weight(source) > can_carry_w(ch) || (get_real_obj_weight(source) + get_real_obj_weight(obj) / obj->count) > obj->value[0]) continue; if (all && arg2[3] == '.' && !nifty_is_name(&arg2[4], source->name)) continue; found = TRUE; if ((IS_OBJ_STAT(source, ITEM_NOGIVE) && !IS_OBJ_STAT(obj, ITEM_NOGIVE)) || (IS_OBJ_STAT(obj, ITEM_NOGIVE) && !IS_OBJ_STAT(source, ITEM_NOGIVE))) continue; if (obj && (IS_UNIQUE(ch, obj) || IS_UNIQUE(ch, source)) && source->item_type == ITEM_CONTAINER) continue; obj_from_room(source); if (source->item_type == ITEM_MONEY) { ch->gold += source->value[0]; extract_obj(source); } else obj_to_obj(source, obj); } else if (source->item_type == src_item1 || source->item_type == src_item2 || source->item_type == src_item3) { found = TRUE; break; } } if (!found) { switch (src_item1) { default: send_to_char("There is nothing appropriate here!\n\r", ch); return; case ITEM_FOUNTAIN: send_to_char("There is no fountain or pool here!\n\r", ch); return; case ITEM_BLOOD: send_to_char("There is no blood pool here!\n\r", ch); return; case ITEM_HERB_CON: send_to_char("There are no herbs here!\n\r", ch); return; case ITEM_HERB: send_to_char("You cannot find any smoking herbs.\n\r", ch); return; } } if (dest_item == ITEM_CONTAINER) { act(AT_ACTION, "You fill $p.", ch, obj, NULL, TO_CHAR); act(AT_ACTION, "$n fills $p.", ch, obj, NULL, TO_ROOM); return; } } if (dest_item == ITEM_CONTAINER) { OBJ_DATA *otmp, *otmp_next; bool found = FALSE; if (source == obj) { send_to_char("You can't fill something with itself!\n\r", ch); return; } switch (source->item_type) { default: /* put something in container */ if (!source->in_room /* disallow inventory items */ || !CAN_WEAR(source, ITEM_TAKE) || (IS_OBJ_STAT(source, ITEM_PROTOTYPE) && !can_take_proto(ch)) || IS_OBJ_STAT(source, ITEM_NOGIVE) || get_ch_carry_weight(ch) + get_obj_weight(source) > can_carry_w(ch) || (get_real_obj_weight(source) + get_real_obj_weight(obj) / obj->count) > obj->value[0]) { send_to_char("You can't do that.\n\r", ch); return; } separate_obj(obj); act(AT_ACTION, "You take $P and put it inside $p.", ch, obj, source, TO_CHAR); act(AT_ACTION, "$n takes $P and puts it inside $p.", ch, obj, source, TO_ROOM); obj_from_room(source); obj_to_obj(source, obj); break; case ITEM_MONEY: send_to_char("You can't do that... yet.\n\r", ch); break; case ITEM_CORPSE_PC: if (IS_NPC(ch)) { send_to_char("You can't do that.\n\r", ch); return; } if (IS_OBJ_STAT(source, ITEM_CLANCORPSE) && !IS_IMMORTAL(ch)) { send_to_char("Your hands fumble. Maybe you better loot a different way.\n\r", ch); return; } if (!IS_OBJ_STAT(source, ITEM_CLANCORPSE)) { send_to_char("Not on PC corpses.\n\r", ch); return; } case ITEM_CONTAINER: if (source->item_type == ITEM_CONTAINER /* don't remove */ && IS_SET(source->value[1], CONT_CLOSED)) { act(AT_PLAIN, "The $d is closed.", ch, NULL, source->name, TO_CHAR); return; } case ITEM_CORPSE_NPC: if ((otmp = source->first_content) == NULL) { send_to_char("It's empty.\n\r", ch); return; } separate_obj(obj); for (; otmp; otmp = otmp_next) { otmp_next = otmp->next_content; if (!CAN_WEAR(otmp, ITEM_TAKE) || (IS_OBJ_STAT(otmp, ITEM_PROTOTYPE) && !can_take_proto(ch)) || get_ch_carry_number(ch) + otmp->count > can_carry_n(ch) || get_ch_carry_weight(ch) + get_obj_weight(otmp) > can_carry_w(ch) || (get_real_obj_weight(source) + get_real_obj_weight(obj) / obj->count) > obj->value[0]) continue; obj_from_obj(otmp); obj_to_obj(otmp, obj); found = TRUE; } if (found) { act(AT_ACTION, "You fill $p from $P.", ch, obj, source, TO_CHAR); act(AT_ACTION, "$n fills $p from $P.", ch, obj, source, TO_ROOM); } else send_to_char("There is nothing appropriate in there.\n\r", ch); break; } return; } if (source->value[1] < 1) { send_to_char("There's none left!\n\r", ch); return; } if (source->count > 1 && source->item_type != ITEM_FOUNTAIN) separate_obj(source); separate_obj(obj); switch (source->item_type) { default: bug("do_fill: got bad item type: %d", source->item_type); send_to_char("Something went wrong...\n\r", ch); return; case ITEM_FOUNTAIN: if (obj->value[1] != 0 && obj->value[2] != 0) { send_to_char("There is already another liquid in it.\n\r", ch); return; } obj->value[2] = 0; obj->value[1] = obj->value[0]; act(AT_ACTION, "You fill $p from $P.", ch, obj, source, TO_CHAR); act(AT_ACTION, "$n fills $p from $P.", ch, obj, source, TO_ROOM); return; case ITEM_BLOOD: if (obj->value[1] != 0 && obj->value[2] != 13) { send_to_char("There is already another liquid in it.\n\r", ch); return; } obj->value[2] = 13; if (source->value[1] < diff) diff = source->value[1]; obj->value[1] += diff; act(AT_ACTION, "You fill $p from $P.", ch, obj, source, TO_CHAR); act(AT_ACTION, "$n fills $p from $P.", ch, obj, source, TO_ROOM); if ((source->value[1] -= diff) < 1) { extract_obj(source); make_bloodstain(ch); } return; case ITEM_HERB: if (obj->value[1] != 0 && obj->value[2] != source->value[2]) { send_to_char("There is already another type of herb in it.\n\r", ch); return; } obj->value[2] = source->value[2]; if (source->value[1] < diff) diff = source->value[1]; obj->value[1] += diff; act(AT_ACTION, "You fill $p with $P.", ch, obj, source, TO_CHAR); act(AT_ACTION, "$n fills $p with $P.", ch, obj, source, TO_ROOM); if ((source->value[1] -= diff) < 1) extract_obj(source); return; case ITEM_HERB_CON: if (obj->value[1] != 0 && obj->value[2] != source->value[2]) { send_to_char("There is already another type of herb in it.\n\r", ch); return; } obj->value[2] = source->value[2]; if (source->value[1] < diff) diff = source->value[1]; obj->value[1] += diff; source->value[1] -= diff; act(AT_ACTION, "You fill $p from $P.", ch, obj, source, TO_CHAR); act(AT_ACTION, "$n fills $p from $P.", ch, obj, source, TO_ROOM); return; case ITEM_DRINK_CON: if (obj->value[1] != 0 && obj->value[2] != source->value[2]) { send_to_char("There is already another liquid in it.\n\r", ch); return; } obj->value[2] = source->value[2]; if (source->value[1] < diff) diff = source->value[1]; obj->value[1] += diff; source->value[1] -= diff; act(AT_ACTION, "You fill $p from $P.", ch, obj, source, TO_CHAR); act(AT_ACTION, "$n fills $p from $P.", ch, obj, source, TO_ROOM); return; } } void do_drink(CHAR_DATA * ch, char *argument) { char arg[MIL]; OBJ_DATA *obj; int amount; int liquid; argument = one_argument(argument, arg); /* munch optional words */ if (!str_cmp(arg, "from") && argument[0] != '\0') argument = one_argument(argument, arg); if (arg[0] == '\0') { for (obj = ch->in_room->first_content; obj; obj = obj->next_content) if ((obj->item_type == ITEM_FOUNTAIN) || (obj->item_type == ITEM_BLOOD)) break; if (!obj) { send_to_char("Drink what?\n\r", ch); return; } } else { if ((obj = get_obj_here(ch, arg)) == NULL) { send_to_char("You can't find it.\n\r", ch); return; } } if (obj->count > 1 && obj->item_type != ITEM_FOUNTAIN) separate_obj(obj); if (!IS_NPC(ch) && ch->pcdata->condition[COND_DRUNK] > 40) { send_to_char("You fail to reach your mouth. *Hic*\n\r", ch); return; } switch (obj->item_type) { default: if (obj->carried_by == ch) { act(AT_ACTION, "$n lifts $p up to $s mouth and tries to drink from it...", ch, obj, NULL, TO_ROOM); act(AT_ACTION, "You bring $p up to your mouth and try to drink from it...", ch, obj, NULL, TO_CHAR); } else { act(AT_ACTION, "$n gets down and tries to drink from $p... (Is $e feeling ok?)", ch, obj, NULL, TO_ROOM); act(AT_ACTION, "You get down on the ground and try to drink from $p...", ch, obj, NULL, TO_CHAR); } break; case ITEM_POTION: if (obj->carried_by == ch) do_quaff(ch, obj->name); else send_to_char("You're not carrying that.\n\r", ch); break; case ITEM_BLOOD: if (IS_VAMPIRE(ch) && !IS_NPC(ch)) { if (obj->timer > 0 /* if timer, must be spilled blood */ && ch->level > 5 && ch->pcdata->condition[COND_BLOODTHIRST] > (5 + ch->level / 10)) { send_to_char("It is beneath you to stoop to drinking blood from the ground!\n\r", ch); send_to_char("Unless in dire need, you'd much rather have blood from a victim's neck!\n\r", ch); return; } if (ch->pcdata->condition[COND_BLOODTHIRST] < (10 + ch->level)) { if (ch->pcdata->condition[COND_FULL] >= 48 || ch->pcdata->condition[COND_THIRST] >= 48) { send_to_char("You are too full to drink any blood.\n\r", ch); return; } if (!oprog_use_trigger(ch, obj, NULL, NULL, NULL)) { act(AT_BLOOD, "$n drinks from the spilled blood.", ch, NULL, NULL, TO_ROOM); set_char_color(AT_BLOOD, ch); send_to_char("You relish in the replenishment of this vital fluid...\n\r", ch); if (obj->value[1] <= 1) { set_char_color(AT_BLOOD, ch); send_to_char("You drink the last drop of blood from the spill.\n\r", ch); act(AT_BLOOD, "$n drinks the last drop of blood from the spill.", ch, NULL, NULL, TO_ROOM); } } gain_condition(ch, COND_BLOODTHIRST, 1); gain_condition(ch, COND_FULL, 1); gain_condition(ch, COND_THIRST, 1); if (--obj->value[1] <= 0) { if (obj->serial == cur_obj) global_objcode = rOBJ_DRUNK; extract_obj(obj); make_bloodstain(ch); } } else send_to_char("Alas... you cannot consume any more blood.\n\r", ch); } else send_to_char("It is not in your nature to do such things.\n\r", ch); break; case ITEM_FOUNTAIN: if (!oprog_use_trigger(ch, obj, NULL, NULL, NULL)) { act(AT_ACTION, "$n drinks from the fountain.", ch, NULL, NULL, TO_ROOM); send_to_char("You take a long thirst quenching drink.\n\r", ch); } if (!IS_NPC(ch)) ch->pcdata->condition[COND_THIRST] = 40; break; case ITEM_DRINK_CON: if (obj->value[1] <= 0) { send_to_char("It is already empty.\n\r", ch); return; } if ((liquid = obj->value[2]) >= LIQ_MAX) { bug("Do_drink: bad liquid number %d.", liquid); liquid = obj->value[2] = 0; } if (!oprog_use_trigger(ch, obj, NULL, NULL, NULL)) { act(AT_ACTION, "$n drinks $T from $p.", ch, obj, liq_table[liquid].liq_name, TO_ROOM); act(AT_ACTION, "You drink $T from $p.", ch, obj, liq_table[liquid].liq_name, TO_CHAR); } amount = 1; /* UMIN(amount, obj->value[1]); */ /* what was this? concentrated drinks? concentrated water too I suppose... sheesh! */ gain_condition(ch, COND_DRUNK, amount * liq_table[liquid].liq_affect[COND_DRUNK]); gain_condition(ch, COND_FULL, amount * liq_table[liquid].liq_affect[COND_FULL]); gain_condition(ch, COND_THIRST, amount * liq_table[liquid].liq_affect[COND_THIRST]); if (!IS_NPC(ch)) { if (ch->pcdata->condition[COND_DRUNK] > 24) send_to_char("You feel quite sloshed.\n\r", ch); else if (ch->pcdata->condition[COND_DRUNK] > 18) send_to_char("You feel very drunk.\n\r", ch); else if (ch->pcdata->condition[COND_DRUNK] > 12) send_to_char("You feel drunk.\n\r", ch); else if (ch->pcdata->condition[COND_DRUNK] > 8) send_to_char("You feel a little drunk.\n\r", ch); else if (ch->pcdata->condition[COND_DRUNK] > 5) send_to_char("You feel light headed.\n\r", ch); if (ch->pcdata->condition[COND_FULL] > 40) send_to_char("You are full.\n\r", ch); if (ch->pcdata->condition[COND_THIRST] > 40) send_to_char("You feel bloated.\n\r", ch); else if (ch->pcdata->condition[COND_THIRST] > 36) send_to_char("Your stomach is sloshing around.\n\r", ch); else if (ch->pcdata->condition[COND_THIRST] > 30) send_to_char("You do not feel thirsty.\n\r", ch); } if (obj->value[3]) { /* The drink was poisoned! */ AFFECT_DATA af; act(AT_POISON, "$n sputters and gags.", ch, NULL, NULL, TO_ROOM); act(AT_POISON, "You sputter and gag.", ch, NULL, NULL, TO_CHAR); ch->mental_state = URANGE(20, ch->mental_state + 5, 100); af.type = gsn_poison; af.duration = 3 * obj->value[3]; af.location = APPLY_NONE; af.modifier = 0; af.bitvector = meb(AFF_POISON); affect_join(ch, &af); } obj->value[1] -= amount; if (obj->value[1] <= 0) { send_to_char("The empty container vanishes.\n\r", ch); if (cur_obj == obj->serial) global_objcode = rOBJ_DRUNK; extract_obj(obj); } break; } WAIT_STATE(ch, PULSE_PER_SECOND); return; } void do_eat(CHAR_DATA * ch, char *argument) { char buf[MSL]; OBJ_DATA *obj; int foodcond; bool hgflag = TRUE; ch_ret retcode; if (argument[0] == '\0') { send_to_char("Eat what?\n\r", ch); return; } if (IS_NPC(ch) || ch->pcdata->condition[COND_FULL] > 5) if (ms_find_obj(ch)) return; if ((obj = find_obj(ch, argument, TRUE)) == NULL) return; if (!IS_IMMORTAL(ch)) { if (obj->item_type != ITEM_FOOD && obj->item_type != ITEM_COOK) { act(AT_ACTION, "$n starts to nibble on $p... ($e must really be hungry)", ch, obj, NULL, TO_ROOM); act(AT_ACTION, "You try to nibble on $p...", ch, obj, NULL, TO_CHAR); return; } if (!IS_NPC(ch) && ch->pcdata->condition[COND_FULL] > 40) { send_to_char("You are too full to eat more.\n\r", ch); return; } } if (!IS_NPC(ch) && !IS_SET(ch->pcdata->flags, PCFLAG_HIGHGAG)) hgflag = FALSE; /* required due to object grouping */ separate_obj(obj); if (obj->in_obj) { if (!hgflag) act(AT_PLAIN, "You take $p from $P.", ch, obj, obj->in_obj, TO_CHAR); act(AT_PLAIN, "$n takes $p from $P.", ch, obj, obj->in_obj, TO_ROOM); } if (ch->fighting && number_percent() > (get_curr_dex(ch) * 2 + 47)) { sprintf(buf, "%s", (ch->in_room->sector_type == SECT_UNDERWATER || ch->in_room->sector_type == SECT_WATER_SWIM || ch->in_room->sector_type == SECT_WATER_NOSWIM) ? "dissolves in the water" : (ch->in_room->sector_type == SECT_AIR || xIS_SET(ch->in_room->room_flags, ROOM_NOFLOOR)) ? "falls far below" : "is trampled underfoot"); act(AT_MAGIC, "$n drops $p, and it $T.", ch, obj, buf, TO_ROOM); if (!hgflag) act(AT_MAGIC, "Oops, $p slips from your hand and $T!", ch, obj, buf, TO_CHAR); } else { if (!oprog_use_trigger(ch, obj, NULL, NULL, NULL)) { if (!obj->action_desc || obj->action_desc[0] == '\0') { act(AT_ACTION, "$n eats $p.", ch, obj, NULL, TO_ROOM); if (!hgflag) act(AT_ACTION, "You eat $p.", ch, obj, NULL, TO_CHAR); } else actiondesc(ch, obj, NULL); } switch (obj->item_type) { case ITEM_PILL: WAIT_STATE(ch, PULSE_PER_SECOND / 3); if (!IS_NPC(ch)) { int condition; condition = ch->pcdata->condition[COND_FULL]; gain_condition(ch, COND_FULL, obj->value[4]); if (condition <= 1 && ch->pcdata->condition[COND_FULL] > 1) send_to_char("You are no longer hungry.\n\r", ch); else if (ch->pcdata->condition[COND_FULL] > 40) send_to_char("You are full.\n\r", ch); } if (obj->value[5] < SPOWER_MIN || obj->value[5] > SPOWER_GREATEST) { obj->value[5] = SPOWER_MIN; bug("Spower on object %s on %s is bad.", obj->name, ch->name); } retcode = obj_cast_spell(obj->value[1], obj->value[5], ch, ch, obj); if (retcode == rNONE) retcode = obj_cast_spell(obj->value[2], obj->value[5], ch, ch, obj); if (retcode == rNONE) retcode = obj_cast_spell(obj->value[3], obj->value[5], ch, ch, obj); break; case ITEM_COOK: case ITEM_FOOD: WAIT_STATE(ch, PULSE_PER_SECOND / 3); if (obj->timer > 0 && obj->value[1] > 0) foodcond = (obj->timer * 10) / obj->value[1]; else foodcond = 10; if (!IS_NPC(ch)) { int condition; condition = ch->pcdata->condition[COND_FULL]; gain_condition(ch, COND_FULL, (obj->value[0] * foodcond) / 10); if (condition <= 1 && ch->pcdata->condition[COND_FULL] > 1) send_to_char("You are no longer hungry.\n\r", ch); else if (ch->pcdata->condition[COND_FULL] > 40) send_to_char("You are full.\n\r", ch); } if (obj->value[3] != 0 || (foodcond < 4 && number_range(0, foodcond + 1) == 0) || (obj->item_type == ITEM_COOK && obj->value[2] == 0)) { /* The food was poisoned! */ AFFECT_DATA af; if (obj->value[3] != 0) { act(AT_POISON, "$n chokes and gags.", ch, NULL, NULL, TO_ROOM); act(AT_POISON, "You choke and gag.", ch, NULL, NULL, TO_CHAR); ch->mental_state = URANGE(20, ch->mental_state + 5, 100); } else { act(AT_POISON, "$n gags on $p.", ch, obj, NULL, TO_ROOM); act(AT_POISON, "You gag on $p.", ch, obj, NULL, TO_CHAR); ch->mental_state = URANGE(15, ch->mental_state + 5, 100); } af.type = gsn_poison; af.duration = 2 * obj->value[0] * (obj->value[3] > 0 ? obj->value[3] : 1); af.location = APPLY_NONE; af.modifier = 0; af.bitvector = meb(AFF_POISON); affect_join(ch, &af); } break; } } if (obj->serial == cur_obj) global_objcode = rOBJ_EATEN; extract_obj(obj); return; } /* Calm your mount and make it nowander again -- Xerves 11/99 */ void do_calmmount(CHAR_DATA * ch, char *argument) { CHAR_DATA *mob; ROOM_INDEX_DATA *room; EXIT_DATA *xit; sh_int mfound = 0; sh_int wper; int dirhold[15]; int x = 0; int hdice; int y = 0; int lastdir = 0; for (mob = ch->in_room->first_person; mob; mob = mob->next_in_room) { if (!xIS_SET(mob->act, ACT_SCARED)) continue; else if (xIS_SET(mob->act, ACT_SCARED) && !xIS_SET(mob->act, ACT_MOUNTABLE)) continue; else { mfound = 1; break; } } if (mfound == 0) { send_to_char("There is no mount here to calm.\n\r", ch); return; } wper = get_curr_lck(ch) + get_curr_cha(ch) + ((get_trust(ch) - get_trust(mob)) * 4); if (wper < 5) wper = 5; if (number_percent() < wper) { xREMOVE_BIT(mob->act, ACT_SCARED); xSET_BIT(mob->act, ACT_NOWANDER); act(AT_ACTION, "You gently reach your hand out and calm the mount.", ch, NULL, NULL, TO_CHAR); act(AT_ACTION, "$n gently reaches $s hand out and calms $N.", ch, NULL, mob, TO_ROOM); } else { if (number_percent() < 6) { act(AT_RED, "$N goes into a rage and attacks $n \n\rinstead of settling down.", ch, NULL, mob, TO_ROOM); act(AT_RED, "You attempt to settle down $N, but that\n\ronly makes $M very irritated.", ch, NULL, mob, TO_CHAR); global_retcode = one_hit(mob, ch, TYPE_UNDEFINED, LM_BODY); return; } else { act(AT_ACTION, "$n tries to settle down $N, but $E refuses to submit", ch, NULL, mob, TO_ROOM); act(AT_ACTION, "You try to settle down $N, but $E refuses to submit.", ch, NULL, mob, TO_CHAR); /* Rather spiffy exit searching and movement, will probably loop it more to make the mount run far away from the player -- Xerves 11/99 */ for (y = 1; y < 11; y++) { room = mob->in_room; x = 0; for (xit = room->first_exit; xit; xit = xit->next) { dirhold[x] = xit->vdir; x++; } hdice = dice(1, x - 1); xit = get_exit(mob->in_room, dirhold[hdice]); /* lastdir holds vdir +1 because north is 0 -- Xerves 11/99 */ if (lastdir > 0 && rev_dir[lastdir - 1] == xit->vdir) { for (;;) { if (x < 1) break; hdice = dice(1, x - 1); xit = get_exit(mob->in_room, dirhold[hdice]); if (rev_dir[lastdir - 1] == xit->vdir) continue; else break; } } if (y > 1) lastdir = xit->vdir + 1; move_char(mob, xit, 0); } return; } } return; } /* Feed your mounts to increase movement, nifty -- Xerves 11/99 */ void do_feedmount(CHAR_DATA * ch, char *argument) { OBJ_DATA *obj; CHAR_DATA *mob; sh_int mfound = 0; if (argument[0] == '\0' || !str_cmp(argument, "")) { send_to_char("Feed your mount what?\n\r", ch); return; } for (mob = ch->in_room->first_person; mob; mob = mob->next_in_room) { if (mob != ch->mount) continue; else { mfound = 1; break; } } if (mfound == 0) { send_to_char("How can you feed your mount if you are not mounted?\n\r", ch); return; } if ((obj = find_obj(ch, argument, TRUE)) == NULL) return; // if (mob->move == mob->max_move) // { // send_to_char( "Your mount is full of stanima, uses this food would be useless.\n\r", ch); // return; // } if (obj->item_type != ITEM_MOUNTFOOD) { act(AT_ACTION, "$n tries to feed $s mount $p, but the mount properly refuses it.", ch, obj, NULL, TO_ROOM); act(AT_ACTION, "You try to feed your mount $p, but the mount refuses to eat it.", ch, obj, NULL, TO_CHAR); return; } separate_obj(obj); if (obj->in_obj) { act(AT_PLAIN, "You take $p from $P.", ch, obj, obj->in_obj, TO_CHAR); act(AT_PLAIN, "$n takes $p from $P.", ch, obj, obj->in_obj, TO_ROOM); } /* Fighting check, blah blah -- Xerves */ if (ch->fighting && number_percent() > (get_curr_dex(ch) * 2 + 48)) { act(AT_MAGIC, "$n tries to fead $s mount with $p, but $e misses and the $s is trampled.", ch, obj, NULL, TO_ROOM); act(AT_MAGIC, "Oops... your food just got trampled.", ch, obj, NULL, TO_CHAR); } else { if (!oprog_use_trigger(ch, obj, NULL, NULL, NULL)) { if (!obj->in_obj) { act(AT_ACTION, "$n feeds $p to $s mount.", ch, obj, NULL, TO_ROOM); act(AT_ACTION, "You feed $p to your mount..", ch, obj, NULL, TO_CHAR); } else if (obj->in_obj) { act(AT_ACTION, "$n pulls $p from $P and feeds $s mount.", ch, obj, obj->in_obj, TO_ROOM); act(AT_ACTION, "You pull $p from $P and feed your mount.", ch, obj, obj->in_obj, TO_CHAR); } } WAIT_STATE(ch, PULSE_PER_SECOND / 3); mob->move += obj->value[0]; if (mob->move > mob->max_move) mob->move = mob->max_move; } if (cur_obj == obj->serial) global_objcode = rOBJ_CHEWED; extract_obj(obj); return; } void do_quaff(CHAR_DATA * ch, char *argument) { OBJ_DATA *obj; ch_ret retcode; bool hgflag = TRUE; if (argument[0] == '\0' || !str_cmp(argument, "")) { send_to_char("Quaff what?\n\r", ch); return; } if (ch->fighting && (obj = get_eq_char(ch, WEAR_SHIELD)) != NULL && IS_OBJ_STAT(obj, ITEM_TWOHANDED)) { send_to_char("You cannot quaff in battle if you have a two-handed shield.\n\r", ch); return; } if ((obj = find_obj(ch, argument, TRUE)) == NULL) return; if (obj->item_type != ITEM_POTION) { if (obj->item_type == ITEM_DRINK_CON) do_drink(ch, obj->name); else { act(AT_ACTION, "$n lifts $p up to $s mouth and tries to drink from it...", ch, obj, NULL, TO_ROOM); act(AT_ACTION, "You bring $p up to your mouth and try to drink from it...", ch, obj, NULL, TO_CHAR); } return; } /* * Empty container check -Shaddai */ if (obj->value[1] == -1 && obj->value[2] == -1 && obj->value[3] == -1) { send_to_char("You suck in nothing but air.\n\r", ch); return; } /* * Fullness checking -Thoric */ if (!IS_NPC(ch) && (ch->pcdata->condition[COND_FULL] >= 48 || ch->pcdata->condition[COND_THIRST] >= 48)) { send_to_char("Your stomach cannot contain any more.\n\r", ch); return; } /* People with nuisance flag feels up quicker. -- Shaddai */ /* Yeah so I can't spell I'm a coder :P --Shaddai */ /* You are now adept at feeling up quickly! -- Blod */ if (!IS_NPC(ch) && ch->pcdata->nuisance && ch->pcdata->nuisance->flags > 3 && (ch->pcdata->condition[COND_FULL] >= (48 - (3 * ch->pcdata->nuisance->flags) + ch->pcdata->nuisance->power) || ch->pcdata->condition[COND_THIRST] >= (48 - (ch->pcdata->nuisance->flags) + ch->pcdata->nuisance->power))) { send_to_char("Your stomach cannot contain any more.\n\r", ch); return; } if (!IS_NPC(ch) && !IS_SET(ch->pcdata->flags, PCFLAG_HIGHGAG)) hgflag = FALSE; separate_obj(obj); if (obj->in_obj) { act(AT_PLAIN, "You take $p from $P.", ch, obj, obj->in_obj, TO_CHAR); act(AT_PLAIN, "$n takes $p from $P.", ch, obj, obj->in_obj, TO_ROOM); } /* * If fighting, chance of dropping potion -Thoric */ if (ch->fighting && number_percent() > (get_curr_dex(ch) * 2 + 48)) { act(AT_MAGIC, "$n fumbles $p and shatters it into fragments.", ch, obj, NULL, TO_ROOM); if (!hgflag) act(AT_MAGIC, "Oops... $p is knocked from your hand and shatters!", ch, obj, NULL, TO_CHAR); } else { if (!oprog_use_trigger(ch, obj, NULL, NULL, NULL)) { if (!obj->in_obj) { act(AT_ACTION, "$n quaffs $p.", ch, obj, NULL, TO_ROOM); if (!hgflag) act(AT_ACTION, "You quaff $p.", ch, obj, NULL, TO_CHAR); } else if (obj->in_obj) { act(AT_ACTION, "$n quaffs $p from $P.", ch, obj, obj->in_obj, TO_ROOM); if (!hgflag) act(AT_ACTION, "You quaff $p from $P.", ch, obj, obj->in_obj, TO_CHAR); } } gain_condition(ch, COND_THIRST, 1); if (!IS_NPC(ch) && ch->pcdata->condition[COND_THIRST] > 43) act(AT_ACTION, "Your stomach is nearing its capacity.", ch, NULL, NULL, TO_CHAR); if (obj->value[5] < SPOWER_MIN || obj->value[5] > SPOWER_GREATEST) { obj->value[5] = SPOWER_MIN; bug("Spower on object %s on %s is bad.", obj->name, ch->name); } retcode = obj_cast_spell(obj->value[1], obj->value[5], ch, ch, obj); if (retcode == rNONE) retcode = obj_cast_spell(obj->value[2], obj->value[5], ch, ch, obj); if (retcode == rNONE) retcode = obj_cast_spell(obj->value[3], obj->value[5], ch, ch, obj); if (ch->fighting) ch->fight_timer = 1; else WAIT_STATE(ch, 2); } if (obj->pIndexData->vnum == OBJ_VNUM_FLASK_BREWING) sysdata.brewed_used++; else sysdata.upotion_val += obj->cost / 100; if (cur_obj == obj->serial) global_objcode = rOBJ_QUAFFED; extract_obj(obj); return; } void do_recite(CHAR_DATA * ch, char *argument) { char arg1[MIL]; char arg2[MIL]; CHAR_DATA *victim; OBJ_DATA *scroll; OBJ_DATA *obj; ch_ret retcode; static char extra[MSL]; int passarg = 0; argument = one_argument(argument, arg1); argument = one_argument(argument, arg2); if (arg1[0] == '\0') { send_to_char("Recite what?\n\r", ch); return; } if (ch->fighting && (obj = get_eq_char(ch, WEAR_SHIELD)) != NULL && IS_OBJ_STAT(obj, ITEM_TWOHANDED)) { send_to_char("You cannot recite in battle if you have a two-handed shield.\n\r", ch); return; } if (ms_find_obj(ch)) return; if ((scroll = get_obj_carry(ch, arg1)) == NULL) { send_to_char("You do not have that scroll.\n\r", ch); return; } if (scroll->item_type != ITEM_SCROLL) { act(AT_ACTION, "$n holds up $p as if to recite something from it...", ch, scroll, NULL, TO_ROOM); act(AT_ACTION, "You hold up $p and stand there with your mouth open. (Now what?)", ch, scroll, NULL, TO_CHAR); return; } if (IS_NPC(ch) && (scroll->pIndexData->vnum == OBJ_VNUM_SCROLL_SCRIBING)) { send_to_char("As a mob, this dialect is foreign to you.\n\r", ch); return; } obj = NULL; if (arg2[0] == '\0') victim = ch; else if (scroll->value[1] != skill_lookup("word of recall") && scroll->value[2] != skill_lookup("word of recall") && scroll->value[3] != skill_lookup("word of recall")) { if ((victim = get_char_room_new(ch, arg2, 1)) == NULL && (obj = get_obj_carry(ch, arg2)) == NULL) { send_to_char("You can't find it.\n\r", ch); return; } } else { victim = ch; sprintf(extra, arg2); target_name = extra; passarg = 1; } if (scroll->pIndexData->vnum == OBJ_VNUM_SCROLL_SCRIBING) sysdata.scribed_used++; separate_obj(scroll); act(AT_MAGIC, "$n recites $p.", ch, scroll, NULL, TO_ROOM); act(AT_MAGIC, "You recite $p.", ch, scroll, NULL, TO_CHAR); if (victim != ch) WAIT_STATE(ch, 6 * PULSE_VIOLENCE); else WAIT_STATE(ch, PULSE_PER_SECOND / 2); if (scroll->value[5] < SPOWER_MIN || scroll->value[5] > SPOWER_GREATEST) { scroll->value[5] = SPOWER_MIN; bug("Spower on object %s on %s is bad.", scroll->name, ch->name); } if (passarg == 1) { retcode = obj_cast_spell(scroll->value[1]+10000, scroll->value[5], ch, victim, obj); if (retcode == rNONE) retcode = obj_cast_spell(scroll->value[2]+10000, scroll->value[5], ch, victim, obj); if (retcode == rNONE) retcode = obj_cast_spell(scroll->value[3]+10000, scroll->value[5], ch, victim, obj); } else { retcode = obj_cast_spell(scroll->value[1], scroll->value[5], ch, victim, obj); if (retcode == rNONE) retcode = obj_cast_spell(scroll->value[2], scroll->value[5], ch, victim, obj); if (retcode == rNONE) retcode = obj_cast_spell(scroll->value[3], scroll->value[5], ch, victim, obj); } if (scroll->serial == cur_obj) global_objcode = rOBJ_USED; extract_obj(scroll); return; } /* * Function to handle the state changing of a triggerobject (lever) -Thoric */ void pullorpush(CHAR_DATA * ch, OBJ_DATA * obj, bool pull) { char buf[MSL]; CHAR_DATA *rch; bool isup; ROOM_INDEX_DATA *room, *to_room; EXIT_DATA *pexit, *pexit_rev; int edir; char *txt; if (IS_SET(obj->value[0], TRIG_UP)) isup = TRUE; else isup = FALSE; switch (obj->item_type) { default: sprintf(buf, "You can't %s that!\n\r", pull ? "pull" : "push"); send_to_char(buf, ch); return; break; case ITEM_SWITCH: case ITEM_LEVER: case ITEM_PULLCHAIN: if ((!pull && isup) || (pull && !isup)) { sprintf(buf, "It is already %s.\n\r", isup ? "up" : "down"); send_to_char(buf, ch); return; } case ITEM_BUTTON: if ((!pull && isup) || (pull && !isup)) { sprintf(buf, "It is already %s.\n\r", isup ? "in" : "out"); send_to_char(buf, ch); return; } break; } if ((pull) && HAS_PROG(obj->pIndexData, PULL_PROG)) { if (!IS_SET(obj->value[0], TRIG_AUTORETURN)) REMOVE_BIT(obj->value[0], TRIG_UP); oprog_pull_trigger(ch, obj); return; } if ((!pull) && HAS_PROG(obj->pIndexData, PUSH_PROG)) { if (!IS_SET(obj->value[0], TRIG_AUTORETURN)) SET_BIT(obj->value[0], TRIG_UP); oprog_push_trigger(ch, obj); return; } if (!oprog_use_trigger(ch, obj, NULL, NULL, NULL)) { sprintf(buf, "$n %s $p.", pull ? "pulls" : "pushes"); act(AT_ACTION, buf, ch, obj, NULL, TO_ROOM); sprintf(buf, "You %s $p.", pull ? "pull" : "push"); act(AT_ACTION, buf, ch, obj, NULL, TO_CHAR); } if (!IS_SET(obj->value[0], TRIG_AUTORETURN)) { if (pull) REMOVE_BIT(obj->value[0], TRIG_UP); else SET_BIT(obj->value[0], TRIG_UP); } if (IS_SET(obj->value[0], TRIG_TELEPORT) || IS_SET(obj->value[0], TRIG_TELEPORTALL) || IS_SET(obj->value[0], TRIG_TELEPORTPLUS)) { int flags; if ((room = get_room_index(obj->value[1])) == NULL) { bug("PullOrPush: obj points to invalid room %d", obj->value[1]); return; } flags = 0; if (IS_SET(obj->value[0], TRIG_SHOWROOMDESC)) SET_BIT(flags, TELE_SHOWDESC); if (IS_SET(obj->value[0], TRIG_TELEPORTALL)) SET_BIT(flags, TELE_TRANSALL); if (IS_SET(obj->value[0], TRIG_TELEPORTPLUS)) SET_BIT(flags, TELE_TRANSALLPLUS); teleport(ch, obj->value[1], flags); return; } if (IS_SET(obj->value[0], TRIG_RAND4) || IS_SET(obj->value[0], TRIG_RAND6)) { int maxd; if ((room = get_room_index(obj->value[1])) == NULL) { bug("PullOrPush: obj points to invalid room %d", obj->value[1]); return; } if (IS_SET(obj->value[0], TRIG_RAND4)) maxd = 3; else maxd = 5; randomize_exits(room, maxd); for (rch = room->first_person; rch; rch = rch->next_in_room) { send_to_char("You hear a loud rumbling sound.\n\r", rch); send_to_char("Something seems different...\n\r", rch); } } if (IS_SET(obj->value[0], TRIG_DOOR)) { room = get_room_index(obj->value[1]); if (!room) room = obj->in_room; if (!room) { bug("PullOrPush: obj points to invalid room %d", obj->value[1]); return; } if (IS_SET(obj->value[0], TRIG_D_NORTH)) { edir = DIR_NORTH; txt = "to the north"; } else if (IS_SET(obj->value[0], TRIG_D_SOUTH)) { edir = DIR_SOUTH; txt = "to the south"; } else if (IS_SET(obj->value[0], TRIG_D_EAST)) { edir = DIR_EAST; txt = "to the east"; } else if (IS_SET(obj->value[0], TRIG_D_WEST)) { edir = DIR_WEST; txt = "to the west"; } else if (IS_SET(obj->value[0], TRIG_D_UP)) { edir = DIR_UP; txt = "from above"; } else if (IS_SET(obj->value[0], TRIG_D_DOWN)) { edir = DIR_DOWN; txt = "from below"; } else { bug("PullOrPush: door: no direction flag set.", 0); return; } pexit = get_exit(room, edir); if (!pexit) { if (!IS_SET(obj->value[0], TRIG_PASSAGE)) { bug("PullOrPush: obj points to non-exit %d", obj->value[1]); return; } to_room = get_room_index(obj->value[2]); if (!to_room) { bug("PullOrPush: dest points to invalid room %d", obj->value[2]); return; } pexit = make_exit(room, to_room, edir); pexit->keyword = STRALLOC(""); pexit->description = STRALLOC(""); pexit->key = -1; pexit->exit_info = 0; top_exit++; act(AT_PLAIN, "A passage opens!", ch, NULL, NULL, TO_CHAR); act(AT_PLAIN, "A passage opens!", ch, NULL, NULL, TO_ROOM); return; } if (IS_SET(obj->value[0], TRIG_UNLOCK) && IS_SET(pexit->exit_info, EX_LOCKED)) { REMOVE_BIT(pexit->exit_info, EX_LOCKED); act(AT_PLAIN, "You hear a faint click $T.", ch, NULL, txt, TO_CHAR); act(AT_PLAIN, "You hear a faint click $T.", ch, NULL, txt, TO_ROOM); if ((pexit_rev = pexit->rexit) != NULL && pexit_rev->to_room == ch->in_room) REMOVE_BIT(pexit_rev->exit_info, EX_LOCKED); return; } if (IS_SET(obj->value[0], TRIG_LOCK) && !IS_SET(pexit->exit_info, EX_LOCKED)) { SET_BIT(pexit->exit_info, EX_LOCKED); act(AT_PLAIN, "You hear a faint click $T.", ch, NULL, txt, TO_CHAR); act(AT_PLAIN, "You hear a faint click $T.", ch, NULL, txt, TO_ROOM); if ((pexit_rev = pexit->rexit) != NULL && pexit_rev->to_room == ch->in_room) SET_BIT(pexit_rev->exit_info, EX_LOCKED); return; } if (IS_SET(obj->value[0], TRIG_OPEN) && IS_SET(pexit->exit_info, EX_CLOSED)) { REMOVE_BIT(pexit->exit_info, EX_CLOSED); for (rch = room->first_person; rch; rch = rch->next_in_room) act(AT_ACTION, "The $d opens.", rch, NULL, pexit->keyword, TO_CHAR); if ((pexit_rev = pexit->rexit) != NULL && pexit_rev->to_room == ch->in_room) { REMOVE_BIT(pexit_rev->exit_info, EX_CLOSED); /* bug here pointed out by Nick Gammon */ for (rch = pexit->to_room->first_person; rch; rch = rch->next_in_room) act(AT_ACTION, "The $d opens.", rch, NULL, pexit_rev->keyword, TO_CHAR); } check_room_for_traps(ch, trap_door[edir]); return; } if (IS_SET(obj->value[0], TRIG_CLOSE) && !IS_SET(pexit->exit_info, EX_CLOSED)) { SET_BIT(pexit->exit_info, EX_CLOSED); for (rch = room->first_person; rch; rch = rch->next_in_room) act(AT_ACTION, "The $d closes.", rch, NULL, pexit->keyword, TO_CHAR); if ((pexit_rev = pexit->rexit) != NULL && pexit_rev->to_room == ch->in_room) { SET_BIT(pexit_rev->exit_info, EX_CLOSED); /* bug here pointed out by Nick Gammon */ for (rch = pexit->to_room->first_person; rch; rch = rch->next_in_room) act(AT_ACTION, "The $d closes.", rch, NULL, pexit_rev->keyword, TO_CHAR); } check_room_for_traps(ch, trap_door[edir]); return; } } } void do_pull(CHAR_DATA * ch, char *argument) { char arg[MIL]; OBJ_DATA *obj; one_argument(argument, arg); if (arg[0] == '\0') { send_to_char("Pull what?\n\r", ch); return; } if (ms_find_obj(ch)) return; if ((obj = get_obj_here(ch, arg)) == NULL) { act(AT_PLAIN, "I see no $T here.", ch, NULL, arg, TO_CHAR); return; } pullorpush(ch, obj, TRUE); } void do_push(CHAR_DATA * ch, char *argument) { char arg[MIL]; OBJ_DATA *obj; one_argument(argument, arg); if (arg[0] == '\0') { send_to_char("Push what?\n\r", ch); return; } if (ms_find_obj(ch)) return; if ((obj = get_obj_here(ch, arg)) == NULL) { act(AT_PLAIN, "I see no $T here.", ch, NULL, arg, TO_CHAR); return; } pullorpush(ch, obj, FALSE); } void do_rap(CHAR_DATA * ch, char *argument) { EXIT_DATA *pexit; char arg[MIL]; one_argument(argument, arg); if (arg[0] == '\0') { send_to_char("Knock on what?\n\r", ch); return; } if (ch->fighting) { send_to_char("You have better things to do with your hands right now.\n\r", ch); return; } if ((pexit = find_door(ch, arg, FALSE)) != NULL) { ROOM_INDEX_DATA *to_room; EXIT_DATA *pexit_rev; char *keyword; if (!IS_SET(pexit->exit_info, EX_CLOSED)) { send_to_char("Why knock? It's open.\n\r", ch); return; } if (IS_SET(pexit->exit_info, EX_SECRET)) keyword = "wall"; else keyword = pexit->keyword; act(AT_ACTION, "You kock loudly on the $d.", ch, NULL, keyword, TO_CHAR); act(AT_ACTION, "$n knocks loudly on the $d.", ch, NULL, keyword, TO_ROOM); if ((to_room = pexit->to_room) != NULL && (pexit_rev = pexit->rexit) != NULL && pexit_rev->to_room == ch->in_room) { CHAR_DATA *rch; for (rch = to_room->first_person; rch; rch = rch->next_in_room) { act(AT_ACTION, "Someone knocks loudly from the other side of the $d.", rch, NULL, pexit_rev->keyword, TO_CHAR); } } } else { act(AT_ACTION, "You make knocking motions through the air.", ch, NULL, NULL, TO_CHAR); act(AT_ACTION, "$n makes knocking motions through the air.", ch, NULL, NULL, TO_ROOM); } return; } /* pipe commands (light, tamp, smoke) by Thoric */ void do_tamp(CHAR_DATA * ch, char *argument) { OBJ_DATA *pipe; char arg[MIL]; one_argument(argument, arg); if (arg[0] == '\0') { send_to_char("Tamp what?\n\r", ch); return; } if (ms_find_obj(ch)) return; if ((pipe = get_obj_carry(ch, arg)) == NULL) { send_to_char("You aren't carrying that.\n\r", ch); return; } if (pipe->item_type != ITEM_PIPE) { send_to_char("You can't tamp that.\n\r", ch); return; } if (!IS_SET(pipe->value[3], PIPE_TAMPED)) { act(AT_ACTION, "You gently tamp $p.", ch, pipe, NULL, TO_CHAR); act(AT_ACTION, "$n gently tamps $p.", ch, pipe, NULL, TO_ROOM); SET_BIT(pipe->value[3], PIPE_TAMPED); return; } send_to_char("It doesn't need tamping.\n\r", ch); } void do_smoke(CHAR_DATA * ch, char *argument) { OBJ_DATA *pipe; char arg[MIL]; one_argument(argument, arg); if (arg[0] == '\0') { send_to_char("Smoke what?\n\r", ch); return; } if (ms_find_obj(ch)) return; if ((pipe = get_obj_carry(ch, arg)) == NULL) { send_to_char("You aren't carrying that.\n\r", ch); return; } if (pipe->item_type != ITEM_PIPE) { act(AT_ACTION, "You try to smoke $p... but it doesn't seem to work.", ch, pipe, NULL, TO_CHAR); act(AT_ACTION, "$n tries to smoke $p... (I wonder what $e's been putting in $s pipe?)", ch, pipe, NULL, TO_ROOM); return; } if (!IS_SET(pipe->value[3], PIPE_LIT)) { act(AT_ACTION, "You try to smoke $p, but it's not lit.", ch, pipe, NULL, TO_CHAR); act(AT_ACTION, "$n tries to smoke $p, but it's not lit.", ch, pipe, NULL, TO_ROOM); return; } if (pipe->value[1] > 0) { if (!oprog_use_trigger(ch, pipe, NULL, NULL, NULL)) { act(AT_ACTION, "You draw thoughtfully from $p.", ch, pipe, NULL, TO_CHAR); act(AT_ACTION, "$n draws thoughtfully from $p.", ch, pipe, NULL, TO_ROOM); } if (IS_VALID_HERB(pipe->value[2]) && pipe->value[2] < top_herb) { int sn = pipe->value[2] + TYPE_HERB; SKILLTYPE *skill = get_skilltype(sn); WAIT_STATE(ch, skill->beats); if (skill->spell_fun) obj_cast_spell(sn, 1, ch, ch, NULL); if (obj_extracted(pipe)) return; } else bug("do_smoke: bad herb type %d", pipe->value[2]); SET_BIT(pipe->value[3], PIPE_HOT); if(pipe->value[4] == -1) { pipe->value[1] = 50; } if (--pipe->value[1] < 1) { REMOVE_BIT(pipe->value[3], PIPE_LIT); SET_BIT(pipe->value[3], PIPE_DIRTY); SET_BIT(pipe->value[3], PIPE_FULLOFASH); } } } void do_light(CHAR_DATA * ch, char *argument) { OBJ_DATA *pipe; char arg[MIL]; one_argument(argument, arg); if (arg[0] == '\0') { send_to_char("Light what?\n\r", ch); return; } if (ms_find_obj(ch)) return; if ((pipe = get_obj_carry(ch, arg)) == NULL) { send_to_char("You aren't carrying that.\n\r", ch); return; } if (pipe->item_type != ITEM_PIPE) { send_to_char("You can't light that.\n\r", ch); return; } if (!IS_SET(pipe->value[3], PIPE_LIT)) { if (pipe->value[1] < 1) { act(AT_ACTION, "You try to light $p, but it's empty.", ch, pipe, NULL, TO_CHAR); act(AT_ACTION, "$n tries to light $p, but it's empty.", ch, pipe, NULL, TO_ROOM); return; } act(AT_ACTION, "You carefully light $p.", ch, pipe, NULL, TO_CHAR); act(AT_ACTION, "$n carefully lights $p.", ch, pipe, NULL, TO_ROOM); SET_BIT(pipe->value[3], PIPE_LIT); return; } send_to_char("It's already lit.\n\r", ch); } void do_empty(CHAR_DATA * ch, char *argument) { OBJ_DATA *obj; char arg1[MIL]; char arg2[MIL]; argument = one_argument(argument, arg1); argument = one_argument(argument, arg2); if (!str_cmp(arg2, "into") && argument[0] != '\0') argument = one_argument(argument, arg2); if (arg1[0] == '\0') { send_to_char("Empty what?\n\r", ch); return; } if (ms_find_obj(ch)) return; if ((obj = get_obj_carry(ch, arg1)) == NULL) { send_to_char("You aren't carrying that.\n\r", ch); return; } if (obj->count > 1) separate_obj(obj); switch (obj->item_type) { default: act(AT_ACTION, "You shake $p in an attempt to empty it...", ch, obj, NULL, TO_CHAR); act(AT_ACTION, "$n begins to shake $p in an attempt to empty it...", ch, obj, NULL, TO_ROOM); return; case ITEM_PIPE: act(AT_ACTION, "You gently tap $p and empty it out.", ch, obj, NULL, TO_CHAR); act(AT_ACTION, "$n gently taps $p and empties it out.", ch, obj, NULL, TO_ROOM); REMOVE_BIT(obj->value[3], PIPE_FULLOFASH); REMOVE_BIT(obj->value[3], PIPE_LIT); obj->value[1] = 0; return; case ITEM_DRINK_CON: if (obj->value[1] < 1) { send_to_char("It's already empty.\n\r", ch); return; } act(AT_ACTION, "You empty $p.", ch, obj, NULL, TO_CHAR); act(AT_ACTION, "$n empties $p.", ch, obj, NULL, TO_ROOM); obj->value[1] = 0; return; case ITEM_CONTAINER: case ITEM_QUIVER: if (IS_SET(obj->value[1], CONT_CLOSED)) { act(AT_PLAIN, "The $d is closed.", ch, NULL, obj->name, TO_CHAR); return; } case ITEM_KEYRING: case ITEM_SHEATH: if (!obj->first_content) { send_to_char("It's already empty.\n\r", ch); return; } if (arg2[0] == '\0') { if (wIS_SET(ch, ROOM_NODROP) || xIS_SET(ch->in_room->room_flags, ROOM_NODROP) || xIS_SET(ch->act, PLR_LITTERBUG)) { set_char_color(AT_MAGIC, ch); send_to_char("A magical force stops you!\n\r", ch); set_char_color(AT_TELL, ch); send_to_char("Someone tells you, 'No littering here!'\n\r", ch); return; } if (wIS_SET(ch, ROOM_NODROPALL) || xIS_SET(ch->in_room->room_flags, ROOM_NODROPALL) || xIS_SET(ch->in_room->room_flags, ROOM_CLANSTOREROOM)) { send_to_char("You can't seem to do that here...\n\r", ch); return; } if (empty_obj(obj, NULL, ch->in_room)) { act(AT_ACTION, "You empty $p.", ch, obj, NULL, TO_CHAR); act(AT_ACTION, "$n empties $p.", ch, obj, NULL, TO_ROOM); if (IS_SET(sysdata.save_flags, SV_DROP)) save_char_obj(ch); } else send_to_char("Hmmm... didn't work.\n\r", ch); } else { OBJ_DATA *dest = get_obj_here(ch, arg2); if (!dest) { send_to_char("You can't find it.\n\r", ch); return; } if (dest == obj) { send_to_char("You can't empty something into itself!\n\r", ch); return; } if (dest->item_type != ITEM_CONTAINER && dest->item_type != ITEM_KEYRING && dest->item_type != ITEM_QUIVER) { send_to_char("That's not a container!\n\r", ch); return; } if (IS_SET(dest->value[1], CONT_CLOSED)) { act(AT_PLAIN, "The $d is closed.", ch, NULL, dest->name, TO_CHAR); return; } separate_obj(dest); if (empty_obj(obj, dest, NULL)) { act(AT_ACTION, "You empty $p into $P.", ch, obj, dest, TO_CHAR); act(AT_ACTION, "$n empties $p into $P.", ch, obj, dest, TO_ROOM); if (!dest->carried_by && IS_SET(sysdata.save_flags, SV_PUT)) save_char_obj(ch); } else act(AT_ACTION, "$P is too full.", ch, obj, dest, TO_CHAR); } return; } } /* * Apply a salve/ointment -Thoric * Support for applying to others. Pkill concerns dealt with elsewhere. */ void do_apply(CHAR_DATA * ch, char *argument) { return; } /* generate an action description message */ void actiondesc(CHAR_DATA * ch, OBJ_DATA * obj, void *vo) { char charbuf[MSL]; char roombuf[MSL]; char *srcptr = obj->action_desc; char *charptr = charbuf; char *roomptr = roombuf; const char *ichar = "You"; const char *iroom = "Someone"; while (*srcptr != '\0') { if (*srcptr == '$') { srcptr++; switch (*srcptr) { case 'e': ichar = "you"; iroom = "$e"; break; case 'm': ichar = "you"; iroom = "$m"; break; case 'n': ichar = "you"; iroom = "$n"; break; case 's': ichar = "your"; iroom = "$s"; break; /*case 'q': iroom = "s"; break; */ default: srcptr--; *charptr++ = *srcptr; *roomptr++ = *srcptr; break; } } else if (*srcptr == '%' && *++srcptr == 's') { ichar = "You"; iroom = "$n"; } else { *charptr++ = *srcptr; *roomptr++ = *srcptr; srcptr++; continue; } while ((*charptr = *ichar) != '\0') { charptr++; ichar++; } while ((*roomptr = *iroom) != '\0') { roomptr++; iroom++; } srcptr++; } *charptr = '\0'; *roomptr = '\0'; switch (obj->item_type) { case ITEM_BLOOD: case ITEM_FOUNTAIN: act(AT_ACTION, charbuf, ch, obj, ch, TO_CHAR); act(AT_ACTION, roombuf, ch, obj, ch, TO_ROOM); return; case ITEM_DRINK_CON: act(AT_ACTION, charbuf, ch, obj, liq_table[obj->value[2]].liq_name, TO_CHAR); act(AT_ACTION, roombuf, ch, obj, liq_table[obj->value[2]].liq_name, TO_ROOM); return; case ITEM_PIPE: return; case ITEM_ARMOR: case ITEM_WEAPON: case ITEM_LIGHT: return; case ITEM_COOK: case ITEM_FOOD: act(AT_ACTION, charbuf, ch, obj, ch, TO_CHAR); act(AT_ACTION, roombuf, ch, obj, ch, TO_ROOM); return; default: return; } return; } // SET_BIT for Wilderness flags void set_bit_wilderness(CHAR_DATA *ch, int bits) { int z; TOWN_DATA *town; if (!IN_WILDERNESS(ch)) return; if (kingdom_sector[ch->map][ch->coord->x][ch->coord->y] < 2) return; for (town = kingdom_table[kingdom_sector[ch->map][ch->coord->x][ch->coord->y]]->first_town; town; town = town->next) { if (in_town_range(town, ch->coord->x, ch->coord->y, ch->map)) { for (z = 1; z <= 150; z++) { if (town->roomcoords[z][0] == ch->coord->x && town->roomcoords[z][1] == ch->coord->y && town->roomcoords[z][2] == ch->map) { xSET_BIT(town->roomflags[z], bits); return; } } } } return; } // REMOVE_BIT for Wilderness flags void remove_bit_wilderness(CHAR_DATA *ch, int bits) { int z; TOWN_DATA *town; if (!IN_WILDERNESS(ch)) return; if (kingdom_sector[ch->map][ch->coord->x][ch->coord->y] < 2) return; for (town = kingdom_table[kingdom_sector[ch->map][ch->coord->x][ch->coord->y]]->first_town; town; town = town->next) { if (in_town_range(town, ch->coord->x, ch->coord->y, ch->map)) { for (z = 1; z <= 150; z++) { if (town->roomcoords[z][0] == ch->coord->x && town->roomcoords[z][1] == ch->coord->y && town->roomcoords[z][2] == ch->map) { xREMOVE_BIT(town->roomflags[z], bits); return; } } } } return; } // IS_SET for Wilderness flags bool is_set_wilderness(CHAR_DATA *ch, int bits, int x, int y, int map) { int z; TOWN_DATA *town; if (!IS_VALID_COORDS(x, y)) return FALSE; if (map < 0 || map >= MAP_MAX) return FALSE; if (kingdom_sector[map][x][y] < 2) return FALSE; for (town = kingdom_table[kingdom_sector[map][x][y]]->first_town; town; town = town->next) { if (in_town_range(town, x, y, ch->map)) { for (z = 1; z <= 150; z++) { if (town->roomcoords[z][0] == x && town->roomcoords[z][1] == y && town->roomcoords[z][2] == map) { if (xIS_SET(town->roomflags[z], bits)) return TRUE; else return FALSE; } } } } return FALSE; } /* * Extended Bitvector Routines -Thoric */ /* check to see if the extended bitvector is completely empty */ bool ext_is_empty(EXT_BV * bits) { int x; for (x = 0; x < XBI; x++) if (bits->bits[x] != 0) return FALSE; return TRUE; } void ext_clear_bits(EXT_BV * bits) { int x; for (x = 0; x < XBI; x++) bits->bits[x] = 0; } /* for use by xHAS_BITS() -- works like IS_SET() */ int ext_has_bits(EXT_BV * var, EXT_BV * bits) { int x, bit; for (x = 0; x < XBI; x++) if ((bit = (var->bits[x] & bits->bits[x])) != 0) return bit; return 0; } /* for use by xSAME_BITS() -- works like == */ bool ext_same_bits(EXT_BV * var, EXT_BV * bits) { int x; for (x = 0; x < XBI; x++) if (var->bits[x] != bits->bits[x]) return FALSE; return TRUE; } /* for use by xSET_BITS() -- works like SET_BIT() */ void ext_set_bits(EXT_BV * var, EXT_BV * bits) { int x; for (x = 0; x < XBI; x++) var->bits[x] |= bits->bits[x]; } /* for use by xREMOVE_BITS() -- works like REMOVE_BIT() */ void ext_remove_bits(EXT_BV * var, EXT_BV * bits) { int x; for (x = 0; x < XBI; x++) var->bits[x] &= ~(bits->bits[x]); } /* for use by xTOGGLE_BITS() -- works like TOGGLE_BIT() */ void ext_toggle_bits(EXT_BV * var, EXT_BV * bits) { int x; for (x = 0; x < XBI; x++) var->bits[x] ^= bits->bits[x]; } /* * Read an extended bitvector from a file. -Thoric */ EXT_BV fread_bitvector(FILE * fp) { EXT_BV ret; int c, x = 0; int num = 0; memset(&ret, '\0', sizeof(ret)); for (;;) { num = fread_number(fp); if (x < XBI) ret.bits[x] = num; ++x; if ((c = getc(fp)) != '&') { ungetc(c, fp); break; } } return ret; } /* return a string for writing a bitvector to a file */ char *print_bitvector(EXT_BV * bits) { static char buf[XBI * 12]; char *p = buf; int x, cnt = 0; for (cnt = XBI - 1; cnt > 0; cnt--) if (bits->bits[cnt]) break; for (x = 0; x <= cnt; x++) { sprintf(p, "%d", bits->bits[x]); p += strlen(p); if (x < cnt) *p++ = '&'; } *p = '\0'; return buf; } /* * Write an extended bitvector to a file -Thoric */ void fwrite_bitvector(EXT_BV * bits, FILE * fp) { fputs(print_bitvector(bits), fp); } EXT_BV meb(int bit) { EXT_BV bits; xCLEAR_BITS(bits); if (bit >= 0) xSET_BIT(bits, bit); return bits; } EXT_BV multimeb(int bit, ...) { EXT_BV bits; va_list param; int b; xCLEAR_BITS(bits); if (bit < 0) return bits; xSET_BIT(bits, bit); va_start(param, bit); while ((b = va_arg(param, int)) != -1) xSET_BIT(bits, b); va_end(param); return bits; } #ifdef WIN32 /* routines not in Windows runtime libraries */ void gettimeofday(struct timeval *tv, struct timezone *tz) { tv->tv_sec = time(0); tv->tv_usec = 0; } /* directory parsing stuff */ DIR *opendir(char *sDirName) { DIR *dp = malloc(sizeof(DIR)); dp->hDirectory = 0; /* if zero, we must do a FindFirstFile */ strcpy(dp->sDirName, sDirName); /* remember for FindFirstFile */ return dp; } struct dirent *readdir(DIR * dp) { /* either read the first entry, or the next entry */ do { if (dp->hDirectory == 0) { dp->hDirectory = FindFirstFile(dp->sDirName, &dp->Win32FindData); if (dp->hDirectory == INVALID_HANDLE_VALUE) return NULL; } else if (!FindNextFile(dp->hDirectory, &dp->Win32FindData)) return NULL; /* skip directories */ } while (dp->Win32FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); /* make a copy of the name string */ dp->dirinfo.d_name = dp->Win32FindData.cFileName; /* return a pointer to the DIR structure */ return &dp->dirinfo; } void closedir(DIR * dp) { if (dp->hDirectory) FindClose(dp->hDirectory); free(dp); } #endif