/****************************************************************************
* [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame | *
* -----------------------------------------------------------| \\._.// *
* SmaugWiz (C) 1998 by Russ Pillsbury (Windows NT version) | (0...0) *
* -----------------------------------------------------------| ).:.( *
* SMAUG (C) 1994, 1995, 1996 by Derek Snider | {o o} *
* -----------------------------------------------------------| / ' ' \ *
* SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus, |~'~.VxvxV.~'~*
* Scryn, Swordbearer, Rennard, Tricops, and Gorog. | *
* ------------------------------------------------------------------------ *
* Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael *
* Chastain, Michael Quan, and Mitchell Tse. *
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik Staerfeldt, Tom Madsen, and Katja Nyboe. *
* ------------------------------------------------------------------------ *
* 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 "stdafx.h"
#include "smaug.h"
#include "SysData.h"
#include "skill.h"
#include "objects.h"
#include "rooms.h"
#include "Exits.h"
#include "descriptor.h"
#include "character.h"
extern int top_exit;
/*
* Fill a container
* Many enhancements added by Thoric (ie: filling non-drink containers)
*/
void do_fill (CCharacter *ch, char *argument)
{
char arg1 [MAX_INPUT_LENGTH];
char arg2 [MAX_INPUT_LENGTH];
CObjData *obj;
CObjData *source;
short dest_item, src_item1, src_item2, src_item3;
int diff;
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')
{
ch->SendText ("Fill what?\n\r");
return;
}
if (ms_find_obj (ch))
return;
if ((obj = get_obj_carry (ch, arg1)) == NULL)
{
ch->SendText ("You do not have that item.\n\r");
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);
ch->SendText ("You cannot fill that.\n\r");
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->GetName (), TO_CHAR);
return;
}
if (get_obj_weight (obj) / obj->count
>= obj->value[0])
{
ch->SendText ("It's already full as it can be.\n\r");
return;
}
}
else
{
diff = obj->value[0] - obj->value[1];
if (diff < 1 || obj->value[1] >= obj->value[0])
{
ch->SendText ("It's already full as it can be.\n\r");
return;
}
}
if (dest_item == ITEM_PIPE
&& IS_SET (obj->value[3], PIPE_FULLOFASH))
{
ch->SendText ("It's full of ashes, and needs to be emptied first.\n\r");
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)
{
ch->SendText ("You don't have that item.\n\r");
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)
{
ch->SendText ("You cannot find that item.\n\r");
return;
}
}
}
else
source = NULL;
if (!source && dest_item == ITEM_PIPE)
{
ch->SendText ("Fill it with what?\n\r");
return;
}
if (! source) {
BOOL found = FALSE;
found = FALSE;
separate_obj (obj);
CObjectList &List = ch->GetInRoom ()->GetContentList ();
POSITION pos = List.GetHeadPosition ();
while (source = List.GetNext (pos)) {
if (dest_item == ITEM_CONTAINER) {
if (! source->CanWear (ITEM_TAKE)
|| (source->IsPrototype () && !can_take_proto (ch))
|| ch->GetCarryWeight () + get_obj_weight (source) > can_carry_w (ch)
|| (get_obj_weight (source) + get_obj_weight (obj)/obj->count)
> obj->value [0])
continue;
if (all && arg2 [3] == '.'
&& !nifty_is_name (&arg2 [4], source->GetName ()))
continue;
obj_from_room (source);
if (source->item_type == ITEM_MONEY) {
ch->AddGold (source->value [0]);
extract_obj (source);
}
else
obj_to_obj (source, obj);
found = TRUE;
}
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:
ch->SendText ("There is nothing appropriate here!\n\r");
return;
case ITEM_FOUNTAIN:
ch->SendText ("There is no fountain or pool here!\n\r");
return;
case ITEM_BLOOD:
ch->SendText ("There is no blood pool here!\n\r");
return;
case ITEM_HERB_CON:
ch->SendText ("There are no herbs here!\n\r");
return;
case ITEM_HERB:
ch->SendText ("You cannot find any smoking herbs.\n\r");
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)
{
CObjData *otmp;
char name[MAX_INPUT_LENGTH];
CCharacter *gch;
char *pd;
BOOL found = FALSE;
if (source == obj)
{
ch->SendText ("You can't fill something with itself!\n\r");
return;
}
switch (source->item_type)
{
default: /* put something in container */
if (!source->in_room /* disallow inventory items */
|| ! source->CanWear (ITEM_TAKE)
|| (source->IsPrototype () && !can_take_proto (ch))
|| ch->GetCarryWeight () + get_obj_weight (source) > can_carry_w (ch)
|| (get_obj_weight (source) + get_obj_weight (obj)/obj->count)
> obj->value[0])
{
ch->SendText ("You can't do that.\n\r");
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:
ch->SendText ("You can't do that... yet.\n\r");
break;
case ITEM_CORPSE_PC:
if (ch->IsNpc ())
{
ch->SendText ("You can't do that.\n\r");
return;
}
if (! source->IsClanCorpse () || ! ch->IsPkiller ()) {
pd = NCCP source->GetShortDescr ();
pd = one_argument (pd, name);
pd = one_argument (pd, name);
pd = one_argument (pd, name);
pd = one_argument (pd, name);
if (str_cmp (name, ch->GetName ()) && ch->IsMortal ())
{
BOOL fGroup;
fGroup = FALSE;
for (gch = first_char; gch; gch = gch->GetNext ())
{
if (!gch->IsNpc ()
&& is_same_group (ch, gch)
&& !str_cmp (name, gch->GetName ()))
{
fGroup = TRUE;
break;
}
}
if (!fGroup)
{
ch->SendText ("That's someone else's corpse.\n\r");
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->GetName (), TO_CHAR);
return;
}
case ITEM_CORPSE_NPC:
if (source->GetContentList ().IsEmpty ()) {
ch->SendText ("It's empty.\n\r");
return;
}
separate_obj (obj);
CObjectList &List = source->GetContentList ();
POSITION pos = List.GetHeadPosition ();
while (otmp = List.GetNext (pos)) {
if (! otmp->CanWear (ITEM_TAKE)
|| (otmp->IsPrototype () && !can_take_proto (ch))
|| ch->carry_number + otmp->count > ch->GetMaxItems ()
|| ch->GetCarryWeight () + get_obj_weight (otmp) > can_carry_w (ch)
|| (get_obj_weight (source) + get_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
ch->SendText ("There is nothing appropriate in there.\n\r");
break;
}
return;
}
if (source->value[1] < 1)
{
ch->SendText ("There's none left!\n\r");
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);
ch->SendText ("Something went wrong...\n\r");
return;
case ITEM_FOUNTAIN:
if (obj->value[1] != 0 && obj->value[2] != 0)
{
ch->SendText ("There is already another liquid in it.\n\r");
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)
{
ch->SendText ("There is already another liquid in it.\n\r");
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])
{
ch->SendText ("There is already another type of herb in it.\n\r");
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])
{
ch->SendText ("There is already another type of herb in it.\n\r");
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])
{
ch->SendText ("There is already another liquid in it.\n\r");
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 (CCharacter *ch, char *argument)
{
char arg[MAX_INPUT_LENGTH];
CObjData *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') {
POSITION pos = ch->GetInRoom ()->GetHeadContentPos ();
while (obj = ch->GetInRoom ()->GetNextContent (pos))
if ((obj->item_type == ITEM_FOUNTAIN)
|| (obj->item_type == ITEM_BLOOD))
break;
if (! obj) {
ch->SendText ("Drink what?\n\r");
return;
}
}
else
{
if ((obj = get_obj_here (ch, arg)) == NULL)
{
ch->SendText ("You can't find it.\n\r");
return;
}
}
if (obj->count > 1 && obj->item_type != ITEM_FOUNTAIN)
separate_obj (obj);
if (!ch->IsNpc () && ch->GetPcData ()->condition[COND_DRUNK] > 40)
{
ch->SendText ("You fail to reach your mouth. *Hic*\n\r");
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, NCCP obj->GetName ());
else
ch->SendText ("You're not carrying that.\n\r");
break;
case ITEM_BLOOD:
if (ch->IsVampire () && !ch->IsNpc ())
{
if (obj->timer > 0 /* if timer, must be spilled blood */
&& ch->GetLevel () > 5
&& ch->GetPcData ()->condition[COND_BLOODTHIRST] > (5+ch->GetLevel ()/10))
{
ch->SendText ("It is above you to stoop to drinking blood from the ground!\n\r");
ch->SendText ("Unless in dire need, you'd much rather have blood from a victim's neck!\n\r");
return;
}
if (ch->GetPcData ()->condition[COND_BLOODTHIRST] < (10 + ch->GetLevel ()))
{
if (ch->GetPcData ()->condition[COND_FULL] >= 48
|| ch->GetPcData ()->condition[COND_THIRST] >= 48)
{
ch->SendText ("You are too full to drink any blood.\n\r");
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);
ch->SendText ("You relish in the replenishment of this vital fluid...\n\r");
if (obj->value[1] <=1)
{
set_char_color (AT_BLOOD, ch);
ch->SendText ("You drink the last drop of blood from the spill.\n\r");
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
ch->SendText ("Alas... you cannot consume any more blood.\n\r");
}
else
ch->SendText ("It is not in your nature to do such things.\n\r");
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);
ch->SendText ("You take a long thirst quenching drink.\n\r");
}
if (!ch->IsNpc ())
ch->GetPcData ()->condition[COND_THIRST] = 40;
break;
case ITEM_DRINK_CON:
if (obj->value[1] <= 0)
{
ch->SendText ("It is already empty.\n\r");
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 (!ch->IsNpc ())
{
if (ch->GetPcData ()->condition[COND_DRUNK] > 24)
ch->SendText ("You feel quite sloshed.\n\r");
else
if (ch->GetPcData ()->condition[COND_DRUNK] > 18)
ch->SendText ("You feel very drunk.\n\r");
else
if (ch->GetPcData ()->condition[COND_DRUNK] > 12)
ch->SendText ("You feel drunk.\n\r");
else
if (ch->GetPcData ()->condition[COND_DRUNK] > 8)
ch->SendText ("You feel a little drunk.\n\r");
else
if (ch->GetPcData ()->condition[COND_DRUNK] > 5)
ch->SendText ("You feel light headed.\n\r");
if (ch->GetPcData ()->condition[COND_FULL] > 40)
ch->SendText ("You are full.\n\r");
if (ch->GetPcData ()->condition[COND_THIRST] > 40)
ch->SendText ("You feel bloated.\n\r");
else
if (ch->GetPcData ()->condition[COND_THIRST] > 36)
ch->SendText ("Your stomach is sloshing around.\n\r");
else
if (ch->GetPcData ()->condition[COND_THIRST] > 30)
ch->SendText ("You do not feel thirsty.\n\r");
}
if (obj->value[3])
{
/* The drink was poisoned! */
CAffectData 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->SetMentalState (URANGE (20, ch->GetMentalState () + 5, 100));
af.type = gsn_poison;
af.duration = 3 * obj->value[3];
af.location = APPLY_NONE;
af.modifier = 0;
af.bitvector = AFF_POISON;
affect_join (ch, &af);
}
obj->value[1] -= amount;
if (obj->value[1] <= 0)
{
ch->SendText ("The empty container vanishes.\n\r");
if (cur_obj == obj->serial)
global_objcode = rOBJ_DRUNK;
extract_obj (obj);
}
break;
}
WAIT_STATE (ch, PULSE_PER_SECOND);
return;
}
void do_eat (CCharacter *ch, char *argument)
{
CObjData *obj;
ch_ret retcode;
int foodcond;
if (argument[0] == '\0')
{
ch->SendText ("Eat what?\n\r");
return;
}
if (ch->IsNpc () || ch->GetPcData ()->condition[COND_FULL] > 5)
if (ms_find_obj (ch))
return;
if ((obj = find_obj (ch, argument, TRUE)) == NULL)
return;
if (ch->IsMortal ())
{
if (obj->item_type != ITEM_FOOD && obj->item_type != ITEM_PILL)
{
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 (!ch->IsNpc () && ch->GetPcData ()->condition[COND_FULL] > 40)
{
ch->SendText ("You are too full to eat more.\n\r");
return;
}
}
/* required due to object grouping */
separate_obj (obj);
if (ch->IsPkiller ())
WAIT_STATE (ch, PULSE_PER_SECOND/4);
else
WAIT_STATE (ch, PULSE_PER_SECOND/2);
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 (!oprog_use_trigger (ch, obj, NULL, NULL, NULL))
{
if (! obj->HasValidActionDescr ())
{
act (AT_ACTION, "$n eats $p.", ch, obj, NULL, TO_ROOM);
act (AT_ACTION, "You eat $p.", ch, obj, NULL, TO_CHAR);
}
else
actiondesc (ch, obj, NULL);
}
switch (obj->item_type)
{
case ITEM_FOOD:
if (obj->timer > 0 && obj->value[1] > 0)
foodcond = (obj->timer * 10) / obj->value[1];
else
foodcond = 10;
if (!ch->IsNpc ())
{
int condition;
condition = ch->GetPcData ()->condition[COND_FULL];
gain_condition (ch, COND_FULL, (obj->value[0] * foodcond) / 10);
if (condition <= 1 && ch->GetPcData ()->condition[COND_FULL] > 1)
ch->SendText ("You are no longer hungry.\n\r");
else if (ch->GetPcData ()->condition[COND_FULL] > 40)
ch->SendText ("You are full.\n\r");
}
if ( obj->value[3] != 0
|| (foodcond < 4 && number_range (0, foodcond + 1) == 0))
{
/* The food was poisoned! */
CAffectData 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->SetMentalState (URANGE (20, ch->GetMentalState () + 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->SetMentalState (URANGE (15, ch->GetMentalState () + 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 = AFF_POISON;
affect_join (ch, &af);
}
break;
case ITEM_PILL:
/* allow pills to fill you, if so desired */
if (!ch->IsNpc () && obj->value[4])
{
int condition;
condition = ch->GetPcData ()->condition[COND_FULL];
gain_condition (ch, COND_FULL, obj->value[4]);
if (condition <= 1 && ch->GetPcData ()->condition[COND_FULL] > 1)
ch->SendText ("You are no longer hungry.\n\r");
else if (ch->GetPcData ()->condition[COND_FULL] > 40)
ch->SendText ("You are full.\n\r");
}
retcode = obj_cast_spell (obj->value[1], obj->value[0], ch, ch, NULL);
if (retcode == rNONE)
retcode = obj_cast_spell (obj->value[2], obj->value[0], ch, ch, NULL);
if (retcode == rNONE)
retcode = obj_cast_spell (obj->value[3], obj->value[0], ch, ch, NULL);
break;
}
if (obj->serial == cur_obj)
global_objcode = rOBJ_EATEN;
extract_obj (obj);
return;
}
void do_quaff (CCharacter *ch, char *argument)
{
CObjData *obj;
ch_ret retcode;
if (argument[0] == '\0' || !str_cmp (argument, ""))
{
ch->SendText ("Quaff what?\n\r");
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, NCCP obj->GetName ());
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;
}
/*
* Fullness checking -Thoric
*/
if (!ch->IsNpc ()
&& (ch->GetPcData ()->condition[COND_FULL] >= 48
|| ch->GetPcData ()->condition[COND_THIRST] >= 48))
{
ch->SendText ("Your stomach cannot contain any more.\n\r");
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);
}
/*
* If fighting, chance of dropping potion -Thoric
*/
if (ch->GetFightData () && number_percent () > (ch->GetDexterity () * 2 + 48))
{
act (AT_MAGIC, "$n accidentally drops $p and it smashes into a thousand fragments.", ch, obj, NULL, TO_ROOM);
act (AT_MAGIC, "Oops... $p gets knocked from your hands and smashes into pieces!", ch, obj, NULL ,TO_CHAR);
}
else
{
if (!oprog_use_trigger (ch, obj, NULL, NULL, NULL))
{
act (AT_ACTION, "$n quaffs $p.", ch, obj, NULL, TO_ROOM);
act (AT_ACTION, "You quaff $p.", ch, obj, NULL, TO_CHAR);
}
if (ch->IsPkiller ())
WAIT_STATE (ch, PULSE_PER_SECOND/4);
else
WAIT_STATE (ch, PULSE_PER_SECOND/2);
gain_condition (ch, COND_THIRST, 1);
retcode = obj_cast_spell (obj->value[1], obj->value[0], ch, ch, NULL);
if (retcode == rNONE)
retcode = obj_cast_spell (obj->value[2], obj->value[0], ch, ch, NULL);
if (retcode == rNONE)
retcode = obj_cast_spell (obj->value[3], obj->value[0], ch, ch, NULL);
}
if (cur_obj == obj->serial)
global_objcode = rOBJ_QUAFFED;
extract_obj (obj);
return;
}
void do_recite (CCharacter *ch, char *argument)
{
char arg1[MAX_INPUT_LENGTH];
char arg2[MAX_INPUT_LENGTH];
CCharacter *victim;
CObjData *scroll;
CObjData *obj;
ch_ret retcode;
argument = one_argument (argument, arg1);
argument = one_argument (argument, arg2);
if (arg1[0] == '\0')
{
ch->SendText ("Recite what?\n\r");
return;
}
if (ms_find_obj (ch))
return;
if ((scroll = get_obj_carry (ch, arg1)) == NULL)
{
ch->SendText ("You do not have that scroll.\n\r");
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 (ch->IsNpc ()
&& (scroll->pIndexData->vnum == OBJ_VNUM_SCROLL_SCRIBING))
{
ch->SendText ("As a mob, this dialect is foreign to you.\n\r");
return;
}
if ((scroll->pIndexData->vnum == OBJ_VNUM_SCROLL_SCRIBING)
&& (ch->GetLevel () + 10 < scroll->value[0]))
{
ch->SendText ("This scroll is too complex for you to understand.\n\r");
return;
}
obj = NULL;
if (arg2[0] == '\0')
victim = ch;
else
{
if ((victim = get_char_room (ch, arg2)) == NULL
&& (obj = get_obj_here (ch, arg2)) == NULL)
{
ch->SendText ("You can't find it.\n\r");
return;
}
}
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, 2 * PULSE_VIOLENCE);
else if (ch->IsPkiller ())
WAIT_STATE (ch, PULSE_PER_SECOND/4);
else
WAIT_STATE (ch, PULSE_PER_SECOND/2);
retcode = obj_cast_spell (scroll->value[1], scroll->value[0], ch, victim, obj);
if (retcode == rNONE)
retcode = obj_cast_spell (scroll->value[2], scroll->value[0], ch, victim, obj);
if (retcode == rNONE)
retcode = obj_cast_spell (scroll->value[3], scroll->value[0], 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 (CCharacter *ch, CObjData *obj, BOOL pull)
{
char buf[MAX_STRING_LENGTH];
CCharacter *rch;
BOOL isup;
CRoomIndexData *room, *to_room;
CExitData *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");
ch->SendText (buf);
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");
ch->SendText (buf);
return;
}
case ITEM_BUTTON:
if ((!pull && isup) || (pull & !isup))
{
sprintf (buf, "It is already %s.\n\r", isup ? "in" : "out");
ch->SendText (buf);
return;
}
break;
}
if (pull && obj->GetIndex ()->HasPullProg ())
{
if (!IS_SET (obj->value[0], TRIG_AUTORETURN))
REMOVE_BIT (obj->value[0], TRIG_UP);
oprog_pull_trigger (ch, obj);
return;
}
if (! pull && obj->GetIndex ()->HasPushProg ())
{
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 = RoomTable.GetRoom (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 = RoomTable.GetRoom (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->GetNextInRoom ())
{
rch->SendText ("You hear a loud rumbling sound.\n\r");
rch->SendText ("Something seems different...\n\r");
}
}
if (IS_SET (obj->value[0], TRIG_DOOR))
{
room = RoomTable.GetRoom (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 = RoomTable.GetRoom (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->SetFlags (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) && pexit->IsLocked ()) {
pexit->ClrLocked ();
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->GetToRoom () == ch->GetInRoom ())
pexit_rev->ClrLocked ();
return;
}
if (IS_SET (obj->value[0], TRIG_LOCK)
&& ! pexit->IsLocked ()) {
pexit->SetLocked ();
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->GetToRoom () == ch->GetInRoom ())
pexit_rev->SetLocked ();
return;
}
if (IS_SET (obj->value [0], TRIG_OPEN)
&& pexit->IsClosed ()) {
pexit->ClrClosed ();
for (rch = room->first_person; rch; rch = rch->GetNextInRoom ())
act (AT_ACTION, "The $d opens.", rch, NULL,
pexit->keyword, TO_CHAR);
if ((pexit_rev = pexit->rexit) != NULL
&& pexit_rev->GetToRoom () == ch->GetInRoom ()) {
pexit_rev->ClrClosed ();
for (rch = pexit->GetToRoom ()->first_person; rch; rch = rch->GetNextInRoom ())
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)
&& ! pexit->IsClosed ()) {
pexit->SetClosed ();
for (rch = room->first_person; rch; rch = rch->GetNextInRoom ())
act (AT_ACTION, "The $d closes.", rch, NULL, pexit->keyword, TO_CHAR);
if ((pexit_rev = pexit->rexit) != NULL
&& pexit_rev->GetToRoom () == ch->GetInRoom ()) {
pexit_rev->SetClosed ();
for (rch = pexit->GetToRoom ()->first_person; rch; rch = rch->GetNextInRoom ())
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 (CCharacter *ch, char *argument)
{
char arg[MAX_INPUT_LENGTH];
CObjData *obj;
one_argument (argument, arg);
if (arg[0] == '\0')
{
ch->SendText ("Pull what?\n\r");
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 (CCharacter *ch, char *argument)
{
char arg[MAX_INPUT_LENGTH];
CObjData *obj;
one_argument (argument, arg);
if (arg[0] == '\0')
{
ch->SendText ("Push what?\n\r");
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 (CCharacter* ch, char* argument)
{
CExitData *pExit;
char arg [MAX_INPUT_LENGTH];
one_argument (argument, arg);
if (arg [0] == '\0') {
ch->SendText ("Rap on what?\n\r");
return;
}
if (ch->GetFightWho ()) {
ch->SendText (
"You have better things to do with your hands right now.\n\r");
return;
}
if (pExit = find_door (ch, arg, FALSE)) {
CRoomIndexData *to_room;
CExitData *pRev;
char *keyword;
if (! pExit->IsClosed ()) {
ch->SendText ("Why knock? It's open.\n\r");
return;
}
if (pExit->IsSecret ())
keyword = "wall";
else
keyword = pExit->keyword;
act (AT_ACTION, "You rap loudly on the $d.", ch, NULL, keyword, TO_CHAR);
act (AT_ACTION, "$n raps loudly on the $d.", ch, NULL, keyword, TO_ROOM);
if ((to_room = pExit->GetToRoom ())
&& (pRev = pExit->rexit)
&& pRev->GetToRoom () == ch->GetInRoom ()) {
CCharacter *rch = to_room->first_person;
for ( ; rch; rch = rch->GetNextInRoom ()) {
act (AT_ACTION,
"Someone raps loudly from the other side of the $d.",
rch, NULL, pRev->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);
}
}
/* pipe commands (light, tamp, smoke) by Thoric */
void do_tamp (CCharacter *ch, char *argument)
{
CObjData *pipe;
char arg[MAX_INPUT_LENGTH];
one_argument (argument, arg);
if (arg[0] == '\0')
{
ch->SendText ("Tamp what?\n\r");
return;
}
if (ms_find_obj (ch))
return;
if ((pipe = get_obj_carry (ch, arg)) == NULL)
{
ch->SendText ("You aren't carrying that.\n\r");
return;
}
if (pipe->item_type != ITEM_PIPE)
{
ch->SendText ("You can't tamp that.\n\r");
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;
}
ch->SendText ("It doesn't need tamping.\n\r");
}
void do_smoke (CCharacter *ch, char *argument)
{
CObjData *pipe;
char arg[MAX_INPUT_LENGTH];
one_argument (argument, arg);
if (arg[0] == '\0')
{
ch->SendText ("Smoke what?\n\r");
return;
}
if (ms_find_obj (ch))
return;
if ((pipe = get_obj_carry (ch, arg)) == NULL)
{
ch->SendText ("You aren't carrying that.\n\r");
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 his $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 (HerbTable.IsValid (pipe->value[2]) && pipe->value[2] < HerbTable.GetCount ())
{
int sn = pipe->value[2] + TYPE_HERB;
CSkill *skill = SkillTable.GetValidSkill (sn);
WAIT_STATE (ch, skill->GetBeats ());
if (skill->GetSpellFunction ())
obj_cast_spell (sn, UMIN (skill->GetMinLevel (), ch->GetLevel ()),
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[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 (CCharacter *ch, char *argument)
{
CObjData *pipe;
char arg[MAX_INPUT_LENGTH];
one_argument (argument, arg);
if (arg[0] == '\0')
{
ch->SendText ("Light what?\n\r");
return;
}
if (ms_find_obj (ch))
return;
if ((pipe = get_obj_carry (ch, arg)) == NULL)
{
ch->SendText ("You aren't carrying that.\n\r");
return;
}
if (pipe->item_type != ITEM_PIPE)
{
ch->SendText ("You can't light that.\n\r");
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;
}
ch->SendText ("It's already lit.\n\r");
}
void do_empty (CCharacter *ch, char *argument)
{
CObjData *obj;
char arg1[MAX_INPUT_LENGTH];
char arg2[MAX_INPUT_LENGTH];
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')
{
ch->SendText ("Empty what?\n\r");
return;
}
if (ms_find_obj (ch))
return;
if ((obj = get_obj_carry (ch, arg1)) == NULL)
{
ch->SendText ("You aren't carrying that.\n\r");
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)
{
ch->SendText ("It's already empty.\n\r");
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:
if (IS_SET (obj->value [1], CONT_CLOSED)) {
act (AT_PLAIN, "The $d is closed.", ch, NULL, obj->GetName (),
TO_CHAR);
return;
}
if (obj->GetContentList ().IsEmpty ()) {
ch->SendText ("It's already empty.\n\r");
return;
}
if (arg2 [0] == '\0') {
if (ch->GetInRoom ()->IsNoDrop ()
|| (! ch->IsNpc () && ch->IsLitterBug ())) {
set_char_color (AT_MAGIC, ch);
ch->SendText ("A magical force stops you!\n\r");
set_char_color (AT_TELL, ch);
ch->SendText ("Someone tells you, 'No littering here!'\n\r");
return;
}
if (ch->GetInRoom ()->IsNoDropAll ()
|| ch->GetInRoom ()->IsClanStoreRoom ()) {
ch->SendText ("You can't seem to do that here...\n\r");
return;
}
if (empty_obj (obj, NULL, ch->GetInRoom ())) {
act (AT_ACTION, "You empty $p.", ch, obj, NULL, TO_CHAR);
act (AT_ACTION, "$n empties $p.", ch, obj, NULL, TO_ROOM);
if (SysData.IsSaveOnDrop ())
save_char_obj (ch);
}
else
ch->SendText ("Hmmm... didn't work.\n\r");
}
else
{
CObjData *dest = get_obj_here (ch, arg2);
if (!dest)
{
ch->SendText ("You can't find it.\n\r");
return;
}
if (dest == obj)
{
ch->SendText ("You can't empty something into itself!\n\r");
return;
}
if (dest->item_type != ITEM_CONTAINER)
{
ch->SendText ("That's not a container!\n\r");
return;
}
if (IS_SET (dest->value[1], CONT_CLOSED))
{
act (AT_PLAIN, "The $d is closed.", ch, NULL, dest->GetName (), 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 && SysData.IsSaveOnPut ())
save_char_obj (ch);
}
else
act (AT_ACTION, "$P is too full.", ch, obj, dest, TO_CHAR);
}
return;
}
}
/*
* Apply a salve/ointment -Thoric
*/
void do_apply (CCharacter *ch, char *argument)
{
CObjData *obj;
ch_ret retcode;
if (argument[0] == '\0')
{
ch->SendText ("Apply what?\n\r");
return;
}
if (ms_find_obj (ch))
return;
if ((obj = get_obj_carry (ch, argument)) == NULL)
{
ch->SendText ("You do not have that.\n\r");
return;
}
if (obj->item_type != ITEM_SALVE)
{
act (AT_ACTION, "$n starts to rub $p on $mself...", ch, obj, NULL, TO_ROOM);
act (AT_ACTION, "You try to rub $p on yourself...", ch, obj, NULL, TO_CHAR);
return;
}
separate_obj (obj);
--obj->value[1];
if (!oprog_use_trigger (ch, obj, NULL, NULL, NULL))
{
if (! obj->HasValidActionDescr ())
{
act (AT_ACTION, "$n rubs $p onto $s body.", ch, obj, NULL, TO_ROOM);
if (obj->value[1] <= 0)
act (AT_ACTION, "You apply the last of $p onto your body.", ch, obj, NULL, TO_CHAR);
else
act (AT_ACTION, "You apply $p onto your body.", ch, obj, NULL, TO_CHAR);
}
else
actiondesc (ch, obj, NULL);
}
WAIT_STATE (ch, obj->value[2]);
retcode = obj_cast_spell (obj->value[4], obj->value[0], ch, ch, NULL);
if (retcode == rNONE)
retcode = obj_cast_spell (obj->value[5], obj->value[0], ch, ch, NULL);
if (!obj_extracted (obj) && obj->value[1] <= 0)
extract_obj (obj);
return;
}
void actiondesc (CCharacter *ch, CObjData *obj, void *vo)
{
char charbuf[MAX_STRING_LENGTH];
char roombuf[MAX_STRING_LENGTH];
const char *srcptr = obj->GetActionDescr ();
char *charptr = charbuf;
char *roomptr = roombuf;
const char *ichar;
const char *iroom;
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 = ch->IsNpc () ? ch->GetShortDescr () : ch->GetName ();
}
else
{
*charptr++ = *srcptr;
*roomptr++ = *srcptr;
srcptr++;
continue;
}
while ((*charptr = *ichar) != '\0')
{
charptr++;
ichar++;
}
while ((*roomptr = *iroom) != '\0')
{
roomptr++;
iroom++;
}
srcptr++;
}
*charptr = '\0';
*roomptr = '\0';
/*
sprintf (buf, "Charbuf: %s", charbuf);
gpDoc->LogString (buf, LOG_HIGH, LEVEL_LESSER);
sprintf (buf, "Roombuf: %s", roombuf);
gpDoc->LogString (buf, LOG_HIGH, LEVEL_LESSER);
*/
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_FOOD:
case ITEM_PILL:
act (AT_ACTION, charbuf, ch, obj, ch, TO_CHAR);
act (AT_ACTION, roombuf, ch, obj, ch, TO_ROOM);
return;
default:
return;
}
return;
}