/*****************************************************
** _________ __ **
** \_ ___ \_____|__| _____ ________ ___ **
** / \ \/_ __ \ |/ \/ ___/_ \/ \ **
** \ \___| | \/ | | | \___ \ / ) | \ **
** \______ /__| |__|__|_| /____ \__/__| / **
** ____\/____ _ \/ ___ \/ \/ **
** \______ \ |_____ __| _/___ **
** | | _/ |\__ \/ __ | __ \ **
** | | \ |_/ __ \ / | ___/_ **
** |_____ /__/____ /_ /___ / **
** \/Antipode\/ \/ \/ **
******************************************************
******************************************************
** Copyright 2000-2003 Crimson Blade **
******************************************************
** Contributors: Noplex, Krowe, Emberlyna, Lanthos **
******************************************************/
/*
* File: liquids.c
* Name: Liquidtable Module (3.02b)
* Author: John 'Noplex' Bellone (jbellone@comcast.net)
* Terms:
* If this file is to be re-disributed; you must send an email
* to the author. All headers above the #include calls must be
* kept intact. All license requirements must be met. License
* can be found in the included license.txt document or on the
* website.
* Description:
* This module is a rewrite of the original module which allowed for
* a SMAUG mud to have a fully online editable liquidtable; adding liquids;
* removing them; and editing them online. It allows an near-endless supply
* of liquids for builder's to work with.
* A second addition to this module allowed for builder's to create mixtures;
* when two liquids were mixed together they would produce a different liquid.
* Yet another adaptation to the above concept allowed for objects to be mixed
* with liquids to produce a liquid.
* This newest version offers a cleaner running code; smaller; and faster in
* all ways around. Hopefully it'll knock out the old one ten fold ;)
* Also in the upcoming 'testing' phase of this code; new additions will be added
* including a better alchemey system for creating poitions as immortals; and as
* mortals.
*/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include "mud.h"
#ifdef KEY
#undef KEY
#endif
#define KEY( literal, field, value ) if ( !str_cmp( word, literal ) ){ field = value; fMatch = TRUE; break;}
#ifndef FCLOSE
#define FCLOSE(fp) fclose(fp); fp=NULL;
#endif
#ifndef NULLSTR
#define NULLSTR(str) (!str || str[0] == '\0')
#endif
char *const liquid_types[LIQTYPE_TOP] =
{
"Beverage", "Alcohol", "Poison", "Blood"
};
char *const mod_types[MAX_CONDS] =
{
"Drunk", "Full", "Thirst", "Bloodthirst"
};
/* locals */
int top_liquid;
int liq_count;
/* liquid i/o functions */
/* save the liquids to the liquidtable.dat file in
* the system directory -Nopey */
void save_liquids(void)
{
FILE *fp = NULL;
LIQ_TABLE *liq = NULL;
char filename[256];
int i;
sprintf(filename, "%sliquidtable.dat", SYSTEM_DIR);
if((fp = fopen(filename, "w")) == NULL)
{
bug("save_liquids(): cannot open %s for writing", filename);
return;
}
fprintf(fp, "#VERSION 3\n");
for(i = 0; i < top_liquid; i++)
{
liq = liquid_table[i];
fprintf(fp, "#LIQUID\n");
fprintf(fp, "Name %s~\n", liq->name);
fprintf(fp, "Shortdesc %s~\n", liq->shortdesc);
fprintf(fp, "Color %s~\n", liq->color);
fprintf(fp, "Type %d\n", liq->type);
fprintf(fp, "Vnum %d\n", liq->vnum);
fprintf(fp, "Mod %d %d %d %d\n", liq->mod[COND_DRUNK], liq->mod[COND_FULL], liq->mod[COND_THIRST], liq->mod[COND_BLOODTHIRST]);
fprintf(fp, "End\n");
}
fprintf(fp, "#END\n");
FCLOSE(fp);
return;
}
/* load the liquids from the liquidtable.dat file in the
* system directory -Nopey */
void load_liquids(void)
{
FILE *fp = NULL;
char filename[256];
int file_version = 0;
sprintf(filename, "%sliquidtable.dat", SYSTEM_DIR);
if((fp = fopen(filename, "r")) == NULL)
{
bug("load_liquids(): cannot open %s for reading", filename);
return;
}
top_liquid = -1;
liq_count = -1;
for( ; ; )
{
char letter = fread_letter(fp);
char *word;
if(letter == '*')
{
fread_to_eol(fp);
continue;
}
if(letter != '#')
{
bug("load_liquids(): # not found (%c)", letter);
return;
}
word = fread_word(fp);
if(!str_cmp(word, "VERSION"))
{
file_version = fread_number(fp);
continue;
}
else
if(!str_cmp(word, "LIQUID"))
{
LIQ_TABLE *liq = fread_liquid(fp);
log_string("debugger: 6");
if(!liq)
bug("load_liquids(): returned NULL liquid");
else
{
static char logger[1024];
sprintf(logger, "debugger: added liquid %s(%d) to table", liq->name, liq->vnum);
log_string(logger);
liquid_table[liq->vnum] = liq;
if(liq->vnum > top_liquid)
top_liquid = liq->vnum;
liq_count++;
}
continue;
}
else
if(!str_cmp(word, "END"))
break;
else
{
bug("load_liquids(): no match for %s", word);
continue;
}
}
FCLOSE(fp);
return;
}
/* read the liquids from a file descriptor and then
* distribute them accordingly to the struct -Nopey */
LIQ_TABLE *fread_liquid(FILE *fp)
{
LIQ_TABLE *liq = NULL;
bool fMatch = FALSE;
int i;
CREATE(liq, LIQ_TABLE, 1);
liq->name = STRALLOC("None");
liq->color = STRALLOC("None");
liq->shortdesc = STRALLOC("None");
liq->vnum = -1;
liq->type = -1;
for(i = 0; i < MAX_CONDS; i++)
liq->mod[i] = -1;
for( ; ; )
{
char *word = feof(fp) ? "End" : fread_word(fp);
switch(UPPER(word[0]))
{
case '*':
fread_to_eol(fp);
break;
case 'C':
KEY("Color", liq->color, fread_string(fp));
break;
case 'E':
if(!str_cmp(word, "End"))
{
if(liq->vnum <= -1)
return NULL;
return liq;
}
break;
case 'N':
KEY("Name", liq->name, fread_string(fp));
break;
case 'M':
if(!str_cmp(word, "Mod"))
{
liq->mod[COND_DRUNK] = fread_number(fp);
liq->mod[COND_FULL] = fread_number(fp);
liq->mod[COND_THIRST] = fread_number(fp);
liq->mod[COND_BLOODTHIRST] = fread_number(fp);
}
break;
case 'S':
KEY("Shortdesc", liq->shortdesc, fread_string(fp));
break;
case 'T':
KEY("Type", liq->type, fread_number(fp));
break;
case 'V':
KEY("Vnum", liq->vnum, fread_number(fp));
break;
}
if(!fMatch)
bug("fread_liquids(): no match for %s", word);
}
/* something went wrong if it gets here */
return NULL;
}
/* save the mixtures to the mixture table -Nopey */
void save_mixtures(void)
{
MIX_TABLE *mix = NULL;
FILE *fp = NULL;
char filename[256];
sprintf(filename, "%smixturetable.dat", SYSTEM_DIR);
if((fp = fopen(filename, "w")) == NULL)
{
bug("save_mixtures(): cannot open %s for writing", filename);
return;
}
fprintf(fp, "#VERSION 3\n");
for(mix = first_mixture; mix; mix = mix->next)
{
fprintf(fp, "#MIXTURE\n");
fprintf(fp, "Name %s~\n", mix->name);
fprintf(fp, "Data %d %d %d\n", mix->data[0], mix->data[1], mix->data[2]);
fprintf(fp, "Object %d\n", mix->object);
fprintf(fp, "End\n");
}
fprintf(fp, "#END\n");
FCLOSE(fp);
return;
}
/* load the mixtures from the mixture table -Nopey */
void load_mixtures(void)
{
FILE *fp = NULL;
char filename[256];
static int file_version = 0;
static bool file_old = FALSE;
sprintf(filename, "%smixturetable.dat", SYSTEM_DIR);
if((fp = fopen(filename, "r")) == NULL)
{
bug("load_mixtures(): cannot open %s for reading", filename);
return;
}
for( ; ; )
{
char letter = fread_letter(fp);
char *word;
if(letter == '*')
{
fread_to_eol(fp);
break;
}
if(letter != '#')
{
bug("load_mixtures(): # not found (%c)", letter);
return;
}
word = fread_word(fp);
if(str_cmp(word, "VERSION"))
{
file_old = TRUE;
continue;
}
else if(!str_cmp(word, "VERSION"))
{
file_version = fread_number(fp);
continue;
}
else
if(!str_cmp(word, "MIXTURE"))
{
MIX_TABLE *mix = NULL;
mix = fread_mixture(fp, file_old);
if(!mix)
bug("load_mixtures(): mixture returned NULL");
else
LINK(mix, first_mixture, last_mixture, next, prev);
}
else if(!str_cmp(word, "END"))
break;
else
{
bug("load_mixtures(): no match for %s", word);
break;
}
}
FCLOSE(fp);
return;
}
/* read the mixtures into the structure -Nopey */
MIX_TABLE *fread_mixture(FILE *fp, bool file_old)
{
MIX_TABLE *mix = NULL;
bool fMatch = FALSE;
CREATE(mix, MIX_TABLE, 1);
mix->name = STRALLOC("");
mix->data[0] = -1;
mix->data[1] = -1;
mix->data[2] = -1;
mix->object = FALSE;
for( ; ; )
{
char *word = feof(fp) ? "End" : fread_word(fp);
switch(UPPER(word[0]))
{
case '*':
fread_to_eol(fp);
break;
case 'D':
if(!str_cmp(word, "Data"))
{
mix->data[0] = fread_number(fp);
mix->data[1] = fread_number(fp);
mix->data[2] = fread_number(fp);
}
break;
case 'E':
if(!str_cmp(word, "End"))
{
if(NULLSTR(mix->name))
mix->name = STRALLOC("Not Set");
return mix;
}
break;
if(file_old)
{
case 'I':
KEY("Into", mix->data[2], fread_number(fp));
break;
}
case 'N':
KEY("Name", mix->name, fread_string(fp));
break;
case 'O':
KEY("Object", mix->object, fread_number(fp));
break;
if(file_old)
{
case 'W':
if(!str_cmp(word, "With"))
{
mix->data[0] = fread_number(fp);
mix->data[1] = fread_number(fp);
}
break;
}
}
if(!fMatch)
bug("fread_mixture(): no match for %s", word);
}
/* something went wrong if it gets here */
return NULL;
}
/* figure out a vnum for the next liquid -Nopey */
static int figure_liq_vnum(void)
{
int i;
/* incase a liquid gets removed; we can fill it's place */
for(i=0; liquid_table[i] != NULL; i++);
/* add to the top */
if(i > top_liquid)
top_liquid = i;
return i;
}
/* lookup func for liquids -Nopey */
LIQ_TABLE *get_liq(char *str)
{
int i;
if(is_number(str))
{
i = atoi(str);
return liquid_table[i];
}
else
{
for(i = 0; i < top_liquid; i++)
if(!str_cmp(liquid_table[i]->name, str))
return liquid_table[i];
}
return NULL;
}
LIQ_TABLE *get_liq_vnum(int vnum)
{
return liquid_table[vnum];
}
/* lookup func for mixtures -Nopey */
MIX_TABLE *get_mix(char *str)
{
MIX_TABLE *mix = NULL;
for(mix = first_mixture; mix; mix = mix->next)
if(!str_cmp(mix->name, str))
return mix;
return NULL;
}
/* olc function for liquids -Nopey */
void do_setliquid(CHAR_DATA *ch, char *argument)
{
char arg[MAX_INPUT_LENGTH];
if(!IS_IMMORTAL(ch) || IS_NPC(ch))
{
send_to_char("Huh?\n\r", ch);
return;
}
argument = one_argument(argument, arg);
if(NULLSTR(arg))
{
send_to_char("Syntax: setliquid <vnum> <field> <value>\n\r"
" setliquid list [vnum]\n\r"
" setliquid create <name>\n\r"
" setliquid delete <vnum>\n\r", ch);
send_to_char(" Fields being one of the following:\n\r"
" name color type shortdesc drunk thrist blood full\n\r", ch);
return;
}
if(!str_cmp(arg, "list"))
{
LIQ_TABLE *liq = NULL;
int i;
if(!liquid_table[0])
{
send_to_char("There is currently no liquids loaded.\n\r", ch);
send_to_char("WARNING:\n\rHaving no liquids loaded will result in no drinks providing\n\r"
"nurishment. This includes water. The default set of liquids\n\r"
"should always be backed up.\n\r", ch);
return;
}
if(!NULLSTR(argument) && ((liq = get_liq(argument)) != NULL))
{
if(!NULLSTR(liq->name))
pager_printf_color(ch, "&GLiquid information for:&g %s\n\r", liq->name);
if(!NULLSTR(liq->shortdesc))
pager_printf_color(ch, "&GLiquid shortdesc:&g\t %s\n\r", liq->shortdesc);
if(!NULLSTR(liq->color))
pager_printf_color(ch, "&GLiquid color:&g\t %s\n\r", liq->color);
pager_printf_color(ch, "&GLiquid vnum:&g\t %d\n\r", liq->vnum);
pager_printf_color(ch, "&GLiquid type:&g\t %s\n\r", liquid_types[liq->type]);
pager_printf_color(ch, "&GLiquid Modifiers\n\r");
for(i = 0; i < MAX_CONDS; i++)
if(liquid_table[i])
pager_printf_color(ch, "&G%s:&g\t %d\n\r", mod_types[i], liq->mod[i]);
return;
}
else if(!NULLSTR(argument) && ((liq = get_liq(argument)) == NULL))
{
send_to_char("Invaild liquid-vnum.\n\rUse 'setliquid list' to gain a vaild liquidvnum.\n\r", ch);
return;
}
pager_printf_color(ch, "&G[&gVnum&G] [&gName&G]\n\r");
for(i = 0; i < top_liquid; i++)
pager_printf_color(ch, " %-7d %s\n\r", liquid_table[i]->vnum, liquid_table[i]->name);
send_to_char("Use 'setliquid list [vnum]' to view individual liquids.\n\r", ch);
send_to_char("Use 'setmixture list' to view the mixturetable.\n\r", ch);
return;
}
else
if(!str_cmp(arg, "create"))
{
LIQ_TABLE *liq = NULL;
int i;
if(liq_count >= MAX_LIQUIDS)
{
send_to_char("Liquid count is at the hard-coded max. Remove some liquids or raise\n\r"
"the hard-coded max number of liquids.\n\r", ch);
return;
}
if(NULLSTR(argument))
{
send_to_char("Syntax: setliquid create <name>\n\r", ch);
return;
}
CREATE(liq, LIQ_TABLE, 1);
liq->name = STRALLOC(argument);
liq->color = STRALLOC("");
liq->shortdesc = STRALLOC(argument);
liq->vnum = figure_liq_vnum( );
liq->type = -1;
for(i = 0; i < MAX_CONDS; i++)
liq->mod[i] = -1;
liquid_table[liq->vnum] = liq;
liq_count++;
send_to_char("Done.\n\r", ch);
save_liquids( );
return;
}
else if(!str_cmp(arg, "delete"))
{
LIQ_TABLE *liq = NULL;
int i = atoi(argument);
if(NULLSTR(argument))
{
send_to_char("Syntax: setliquid delete <vnum>\n\r", ch);
return;
}
if((liq = get_liq_vnum(i)) == NULL)
{
send_to_char("No such vnum. Use 'setliquid list' to gain the vnums.\n\r", ch);
return;
}
if(!NULLSTR(liq->name))
STRFREE(liq->name);
if(!NULLSTR(liq->color))
STRFREE(liq->color);
if(!NULLSTR(liq->shortdesc))
STRFREE(liq->shortdesc);
if(liq->vnum >= top_liquid)
{
int j;
for(j = 0; j != liq->vnum; j++)
if(j > top_liquid)
top_liquid = j;
}
liquid_table[liq->vnum] = NULL;
liq_count--;
DISPOSE(liq);
send_to_char("Done.\n\r", ch);
save_liquids( );
return;
}
else
{
char arg2[MAX_INPUT_LENGTH];
LIQ_TABLE *liq = NULL;
argument = one_argument(argument, arg2);
if(NULLSTR(arg2))
{
send_to_char("Syntax: setliquid <vnum> <field> <value>\n\r", ch);
send_to_char(" Fields being one of the following:\n\r"
" name color shortdesc drunk thrist blood full\n\r", ch);
return;
}
if((liq = get_liq(arg)) == NULL)
{
send_to_char("Invaild liquid-name or vnum.\n\r", ch);
return;
}
if(!str_cmp(arg2, "name"))
{
if(NULLSTR(argument))
{
send_to_char("Syntax: setliquid <vnum> name <name>\n\r", ch);
return;
}
liq->name = STRALLOC(argument);
}
else
if(!str_cmp(arg2, "color"))
{
if(NULLSTR(argument))
{
send_to_char("Syntax: setliquid <vnum> color <color>\n\r", ch);
return;
}
liq->color = STRALLOC(argument);
}
else
if(!str_cmp(arg2, "shortdesc"))
{
if(NULLSTR(argument))
{
send_to_char("Syntax: setliquid <vnum> shortdesc <shortdesc>\n\r", ch);
return;
}
liq->shortdesc = STRALLOC(argument);
}
else if(!str_cmp(arg2, "type"))
{
char arg3[MAX_INPUT_LENGTH];
int i;
bool found = FALSE;
argument = one_argument(argument, arg3);
/* bah; forgot to add this shit -- */
for(i = 0; i < LIQTYPE_TOP; i++)
if(!str_cmp(arg3, liquid_types[i]))
{
found = TRUE;
liq->type = i;
}
if(!found)
{
send_to_char("Syntax: setliquid <vnum> type <liquidtype>\n\r", ch);
return;
}
}
else
{
int i;
bool found = FALSE;
static char * const arg_names[MAX_CONDS] =
{ "drunk", "full", "thirst", "blood" };
if(NULLSTR(argument))
{
send_to_char("Syntax: setliquid <vnum> <field> <value>\n\r", ch);
send_to_char(" Fields being one of the following:\n\r"
" name color shortdesc drunk thrist blood full\n\r", ch);
return;
}
for(i = 0; i < MAX_CONDS; i++)
if(!str_cmp(arg2, arg_names[i]))
{
found = TRUE;
liq->mod[i] = atoi(argument);
}
if(!found)
{
do_setliquid(ch, "");
return;
}
}
send_to_char("Done.\n\r", ch);
save_liquids( );
return;
}
}
/* olc funciton for mixtures -Nopey */
void do_setmixture(CHAR_DATA *ch, char *argument)
{
char arg[MAX_INPUT_LENGTH];
if(!IS_IMMORTAL(ch) || IS_NPC(ch))
{
send_to_char("Huh?\n\r", ch);
return;
}
argument = one_argument(argument, arg);
if(NULLSTR(arg))
{
send_to_char("Syntax: setmixture create <name>\n\r"
" setmixture delete <name>\n\r"
" setmixture list [name]\n\r"
" setmixture <name> <field> <value>\n\r", ch);
send_to_char(" Fields being one of the following:\n\r"
" name vnum1 vnum2 into object\n\r", ch);
return;
}
if(!str_cmp(arg, "list"))
{
MIX_TABLE *mix = NULL;
if(!NULLSTR(argument) && ((mix = get_mix(argument)) != NULL))
{
if(!mix->object)
pager_printf_color(ch,
"&G%s&g mixes with two liquids; &G%d&g and &G%d&g\n\r", mix->name, mix->data[0], mix->data[1]);
else
pager_printf_color(ch,
"&G%s&g mixes with one object; &G%d&g; and one liquid, &G%d&g\n\r", mix->name, mix->data[0], mix->data[1]);
pager_printf_color(ch, "&G%s&g mixes into liquid &G%d&g\n\r", mix->name, mix->data[2]);
return;
}
else if(!NULLSTR(argument) && ((mix = get_mix(argument)) == NULL))
{
send_to_char("Invaild mixture-name.\n\rUse 'setmixture list' to gain a vaild name.\n\r", ch);
return;
}
if(!first_mixture)
{
send_to_char("There is currently no mixtures loaded.\n\r", ch);
return;
}
/* BUGFIX - thanks to Samson */
send_to_pager_color("&G[&gType&G] &G[&gName&G]\n\r", ch);
for(mix = first_mixture; mix; mix = mix->next)
pager_printf_color(ch, " %-8s %s", mix->object ? "Object" : "Liquids", mix->name);
pager_printf_color(ch, "Use 'setmixture list [name]' to view individual mixtures.\n\r");
pager_printf_color(ch, "Use 'setliquid list' to view the liquidtable.\n\r");
return;
}
else
if(!str_cmp(arg, "create"))
{
MIX_TABLE *mix = NULL;
if(NULLSTR(argument))
{
send_to_char("Syntax: setmixture create <name>\n\r", ch);
return;
}
CREATE(mix, MIX_TABLE, 1);
mix->name = STRALLOC(argument);
mix->data[0] = -1;
mix->data[1] = -1;
mix->data[2] = -1;
mix->object = FALSE;
LINK(mix, first_mixture, last_mixture, next, prev);
send_to_char("Done.\n\r", ch);
save_mixtures( );
return;
}
else if(!str_cmp(arg, "delete"))
{
MIX_TABLE *mix = NULL;
if(NULLSTR(argument))
{
send_to_char("Syntax: setmixture delete <name>\n\r", ch);
return;
}
if((mix = get_mix(argument)) == NULL)
{
send_to_char("That's not a mixture name.\n\r", ch);
return;
}
UNLINK(mix, first_mixture, last_mixture, next, prev);
if(!NULLSTR(mix->name))
STRFREE(mix->name);
DISPOSE(mix);
send_to_char("Done.\n\r", ch);
save_mixtures( );
return;
}
else
{
char arg2[MAX_INPUT_LENGTH];
MIX_TABLE *mix = NULL;
if(NULLSTR(arg) || ((mix = get_mix(arg)) == NULL))
{
send_to_char("Syntax: setmixture <mixname> <field> <value>\n\r", ch);
send_to_char(" Fields being one of the following:\n\r"
" name vnum1 vnum2 into object\n\r", ch);
return;
}
argument = one_argument(argument, arg2);
if(!str_cmp(arg2, "name"))
{
if(NULLSTR(argument))
{
send_to_char("Syntax: setmixture <mixname> name <name>\n\r", ch);
return;
}
mix->name = STRALLOC(argument);
}
else if(!str_cmp(arg2, "vnum1"))
{
int i = atoi(argument);
if(NULLSTR(argument))
{
send_to_char("Syntax: setmixture <mixname> vnum1 <liqvnum>\n\r", ch);
return;
}
mix->data[0] = i;
}
else if(!str_cmp(arg2, "vnum2"))
{
int i = atoi(argument);
if(NULLSTR(argument))
{
send_to_char("Syntax: setmixture <mixname> vnum2 <liqvnum>\n\r", ch);
return;
}
mix->data[1] = i;
}
else if(!str_cmp(arg2, "object"))
{
mix->object = !mix->object;
if(mix->object)
send_to_char("Mixture -vnum2- is now an object-vnum.\n\r", ch);
else
send_to_char("Both mixture vnums are now liquids.\n\r", ch);
}
else if(!str_cmp(arg2, "into"))
{
int i = atoi(argument);
if(NULLSTR(argument))
{
send_to_char("Syntax: setmixture <mixname> into <liqvnum>\n\r", ch);
return;
}
mix->data[2] = i;
}
send_to_char("Done.\n\r", ch);
save_mixtures( );
return;
}
}
/* the actual -mix- funciton -Nopey */
void do_mix(CHAR_DATA *ch, char *argument)
{
char arg[MAX_INPUT_LENGTH];
OBJ_DATA *iObj, *tObj = NULL;
argument = one_argument(argument, arg);
/* null arguments */
if(NULLSTR(arg) || NULLSTR(argument))
{
send_to_char("What would you like to mix together?\n\r", ch);
return;
}
/* check for objects in the inventory */
if(((iObj = get_obj_carry(ch, arg)) == NULL) || ((tObj = get_obj_carry(ch, argument)) == NULL))
{
send_to_char("You aren't carrying that.\n\r", ch);
return;
}
/* check itemtypes */
if((iObj->item_type != ITEM_DRINK_CON && iObj->item_type != ITEM_DRINK_MIX)
|| (tObj->item_type != ITEM_DRINK_CON && tObj->item_type != ITEM_DRINK_MIX))
{
send_to_char("You can't mix that!\n\r", ch);
return;
}
/* check to see if it's empty or not */
if(iObj->value[1] <= 0 || tObj->value[1] <= 0)
{
send_to_char("It's empty.\n\r", ch);
return;
}
/* two liquids */
if(iObj->item_type == ITEM_DRINK_CON && tObj->item_type == ITEM_DRINK_CON)
{
/* check to see if the two liquids can be mixed together
* and return the final liquid -Nopey */
if(!liq_can_mix(iObj, tObj))
{
send_to_char("Those two don't mix well together.\n\r", ch);
return;
}
}
else if(iObj->item_type == ITEM_DRINK_MIX && tObj->item_type == ITEM_DRINK_CON)
{
if(!liqobj_can_mix(tObj, iObj))
{
send_to_char("Those two don't mix well together.\n\r", ch);
return;
}
}
else if(iObj->item_type == ITEM_DRINK_CON && tObj->item_type == ITEM_DRINK_MIX)
{
if(!liqobj_can_mix(iObj, tObj))
{
send_to_char("Those two don't mix well together.\n\r", ch);
return;
}
}
else
{
send_to_char("Those two don't mix well together.\n\r", ch);
return;
}
send_to_char_color("&cYou mix them together.&g\n\r", ch);
return;
}
/* mix a liquid with a liquid; return the final product -Nopey */
LIQ_TABLE *liq_can_mix(OBJ_DATA *iObj, OBJ_DATA *tObj)
{
MIX_TABLE *mix = NULL;
bool mix_found = FALSE;
for(mix = first_mixture; mix; mix = mix->next)
if(mix->data[0] == iObj->value[2] || mix->data[1] == iObj->value[2])
{
mix_found = TRUE;
break;
}
if(!mix_found)
return NULL;
if(mix->data[2] > -1)
{
LIQ_TABLE *liq = NULL;
if((liq = get_liq_vnum(mix->data[2])) == NULL)
return NULL;
else
{
iObj->value[1] += tObj->value[1];
iObj->value[2] = liq->vnum;
tObj->value[1] = 0;
tObj->value[2] = -1;
return liq;
}
}
return NULL;
}
/* used to mix an object with a liquid to form
* another liquid; returns the result -Nopey */
LIQ_TABLE *liqobj_can_mix(OBJ_DATA *iObj, OBJ_DATA *oLiq)
{
MIX_TABLE *mix = NULL;
bool mix_found = FALSE;
for(mix = first_mixture; mix; mix = mix->next)
if(mix->object && (mix->data[0] == iObj->value[2] || mix->data[1] == iObj->value[2]))
if(mix->data[0] == oLiq->value[2] || mix->data[1] == oLiq->value[2])
{
mix_found = TRUE;
break;
}
if(!mix_found)
return NULL;
if(mix->data[2] > -1)
{
LIQ_TABLE *liq = NULL;
if((liq = get_liq_vnum(mix->data[2])) == NULL)
return NULL;
else
{
oLiq->value[1] += iObj->value[1];
oLiq->value[2] = liq->vnum;
obj_from_char(iObj);
extract_obj(iObj);
return liq;
}
}
return NULL;
}
/* modified do_drink function -Nopey */
void do_drink( CHAR_DATA *ch, char *argument )
{
char arg[MAX_INPUT_LENGTH];
OBJ_DATA *obj;
AFFECT_DATA af;
int amount;
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 )
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] > MAX_COND_VALUE - 8 )
{
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_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] >= 100
|| ch->pcdata->condition[COND_THIRST] >= 100 )
{
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_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_FOUNTAIN:
{
LIQ_TABLE *liq = NULL;
if(obj->value[1] <= 0)
obj->value[1] = MAX_COND_VALUE;
if((liq = get_liq_vnum(obj->value[2])) == NULL)
{
bug( "Do_drink: bad liquid number %d.", obj->value[2] );
liq = get_liq_vnum( 0 );
}
if(!IS_NPC(ch) && obj->value[2] != 0)
{
gain_condition(ch, COND_THIRST, liq->mod[COND_THIRST]);
gain_condition(ch, COND_FULL, liq->mod[COND_FULL]);
gain_condition(ch, COND_DRUNK, liq->mod[COND_DRUNK]);
if(IS_VAMPIRE(ch))
gain_condition(ch, COND_BLOODTHIRST, liq->mod[COND_BLOODTHIRST]);
}
else if(!IS_NPC(ch) && obj->value[2] == 0)
ch->pcdata->condition[COND_THIRST] = 200;
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 );
}
break;
}
case ITEM_DRINK_CON:
{
LIQ_TABLE *liq = NULL;
if( obj->value[1] <= 0 )
{
send_to_char( "It is already empty.\n\r", ch );
return;
}
/* allow water to be drank; but nothing else on a full stomach -Nopey */
/* added is_npc check; thanks to Olcerin */
if(!IS_NPC(ch) && (ch->pcdata->condition[COND_THIRST] == MAX_COND_VALUE || ch->pcdata->condition[COND_FULL] == MAX_COND_VALUE))
{
send_to_char( "Your stomach is too full to drink anymore!\n\r", ch );
return;
}
if ( ( liq = get_liq_vnum(obj->value[2]) ) == NULL )
{
bug( "Do_drink: bad liquid number %d.", obj->value[2] );
liq = get_liq_vnum( 0 );
}
if ( !oprog_use_trigger( ch, obj, NULL, NULL, NULL ) )
{
act( AT_ACTION, "$n drinks $T from $p.", ch, obj, liq->shortdesc, TO_ROOM );
act( AT_ACTION, "You drink $T from $p.", ch, obj, liq->shortdesc, TO_CHAR );
}
amount = 1; /* UMIN(amount, obj->value[1]); */
/* gain conditions accordingly -Nopey */
gain_condition( ch, COND_DRUNK, liq->mod[COND_DRUNK] );
gain_condition( ch, COND_FULL, liq->mod[COND_FULL] );
gain_condition( ch, COND_THIRST, liq->mod[COND_THIRST] );
if(IS_VAMPIRE(ch))
gain_condition( ch, COND_BLOODTHIRST, liq->mod[COND_BLOODTHIRST] );
if( liq->type == LIQTYPE_POISON )
{
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 = obj->value[3];
af.location = APPLY_NONE;
af.modifier = 0;
af.bitvector = meb(AFF_POISON);
affect_join( ch, &af );
}
if( !IS_NPC(ch) )
{
if( ch->pcdata->condition[COND_DRUNK] > ( MAX_COND_VALUE / 2 ) && ch->pcdata->condition[COND_DRUNK] < ( MAX_COND_VALUE * .4 ) )
send_to_char( "You feel quite sloshed.\n\r", ch );
else if( ch->pcdata->condition[COND_DRUNK] >= ( MAX_COND_VALUE * .4 ) && ch->pcdata->condition[COND_DRUNK] < ( MAX_COND_VALUE * .6 ) )
send_to_char( "You start to feel a little drunk.\n\r", ch );
else if( ch->pcdata->condition[COND_DRUNK] >= ( MAX_COND_VALUE * .6 ) && ch->pcdata->condition[COND_DRUNK] < ( MAX_COND_VALUE * .9 ) )
send_to_char( "Your vision starts to get blurry.\n\r", ch );
else if( ch->pcdata->condition[COND_DRUNK] >= ( MAX_COND_VALUE * .9 ) && ch->pcdata->condition[COND_DRUNK] < MAX_COND_VALUE )
send_to_char( "You feel very drunk.\n\r", ch );
else if( ch->pcdata->condition[COND_DRUNK] == MAX_COND_VALUE )
send_to_char( "You feel like your going to pass out.\n\r", ch );
if( ch->pcdata->condition[COND_THIRST] > ( MAX_COND_VALUE / 2 ) && ch->pcdata->condition[COND_THIRST] < ( MAX_COND_VALUE * .4 ) )
send_to_char( "Your stomach begins to slosh around.\n\r", ch );
else if( ch->pcdata->condition[COND_THIRST] >= ( MAX_COND_VALUE * .4 ) && ch->pcdata->condition[COND_THIRST] < ( MAX_COND_VALUE * .6 ) )
send_to_char( "You start to feel bloated.\n\r", ch );
else if( ch->pcdata->condition[COND_THIRST] >= ( MAX_COND_VALUE * .6 ) && ch->pcdata->condition[COND_THIRST] < ( MAX_COND_VALUE * .9 ) )
send_to_char( "You feel bloated.\n\r", ch );
else if( ch->pcdata->condition[COND_THIRST] >= ( MAX_COND_VALUE * .9 ) && ch->pcdata->condition[COND_THIRST] < MAX_COND_VALUE )
send_to_char( "You stomach is almost filled to it's brim!\n\r", ch );
else if( ch->pcdata->condition[COND_THIRST] == MAX_COND_VALUE)
send_to_char( "Your stomach is full, you can't manage to get anymore down.\n\r", ch );
/* Hopefully this is the reason why that crap was happening. =0P */
if( IS_VAMPIRE(ch) )
{
if( ch->pcdata->condition[COND_BLOODTHIRST] > ( MAX_COND_VALUE / 2 ) && ch->pcdata->condition[COND_BLOODTHIRST] < ( MAX_COND_VALUE * .4 ) )
send_to_char_color( "&rYou replenish your body with the vidal fluid.\n\r", ch );
else if( ch->pcdata->condition[COND_BLOODTHIRST] >= ( MAX_COND_VALUE * .4 ) && ch->pcdata->condition[COND_BLOODTHIRST] < ( MAX_COND_VALUE * .6 ) )
send_to_char_color( "&rYour thirst for blood begins to decrease.\n\r", ch );
else if( ch->pcdata->condition[COND_BLOODTHIRST] >= ( MAX_COND_VALUE *.6 ) && ch->pcdata->condition[COND_BLOODTHIRST] < ( MAX_COND_VALUE * .9 ) )
send_to_char_color( "&rThe thirst for blood begins to leave you...\n\r", ch );
else if( ch->pcdata->condition[COND_BLOODTHIRST] >= ( MAX_COND_VALUE * .9 ) && ch->pcdata->condition[COND_BLOODTHIRST] < MAX_COND_VALUE )
send_to_char( "&rYou drink the last drop of the fluid, the thirst for more leaves your body.\n\r", ch );
}
else if( !IS_VAMPIRE(ch) && ch->pcdata->condition[COND_BLOODTHIRST] >= MAX_COND_VALUE)
{
ch->pcdata->condition[COND_BLOODTHIRST] = MAX_COND_VALUE;
}
}
obj->value[1] -= amount;
if ( obj->value[1] <= 0 ) /* Come now, what good is a drink container that vanishes?? */
{
obj->value[1] = 0; /* Prevents negative values - Samson */
send_to_char( "You drink the last drop from your container.\n\r", ch );
if ( cur_obj == obj->serial )
global_objcode = rOBJ_DRUNK;
/* extract_obj( obj ); Modified 4-21-98 - Samson */
}
break;
}
}
if ( who_fighting( ch ) && IS_PKILL( ch ) )
WAIT_STATE( ch, PULSE_PER_SECOND/3 );
else
WAIT_STATE( ch, PULSE_PER_SECOND );
return;
}
/* standard liquid functions -Nopey */
void do_fill( CHAR_DATA *ch, char *argument )
{
char arg1[MAX_INPUT_LENGTH];
char arg2[MAX_INPUT_LENGTH];
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 = MAX_COND_VALUE;
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))
|| ch->carry_weight + 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;
obj_from_room(source);
if ( source->item_type == ITEM_MONEY )
{
ch->gold += 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:
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;
char name[MAX_INPUT_LENGTH];
CHAR_DATA *gch;
char *pd;
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))
|| ch->carry_weight + 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 )
|| !IS_SET( ch->pcdata->flags, PCFLAG_DEADLY ) )
{
pd = source->short_descr;
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->name ) && !IS_IMMORTAL(ch) )
{
bool fGroup;
fGroup = FALSE;
for ( gch = first_char; gch; gch = gch->next )
{
if ( !IS_NPC(gch)
&& is_same_group( ch, gch )
&& !str_cmp( name, gch->name ) )
{
fGroup = TRUE;
break;
}
}
if ( !fGroup )
{
send_to_char( "That's someone else's corpse.\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))
|| ch->carry_number + otmp->count > can_carry_n(ch)
|| ch->carry_weight + 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_empty( CHAR_DATA *ch, char *argument )
{
OBJ_DATA *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' )
{
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:
if ( !obj->first_content )
{
send_to_char( "It's already empty.\n\r", ch );
return;
}
if ( arg2[0] == '\0' )
{
if ( 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 ( 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_EMPTY ) )
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_EMPTY ) )
save_char_obj( ch );
}
else
act( AT_ACTION, "$P is too full.", ch, obj, dest, TO_CHAR );
}
return;
}
}