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