/****************************************************************************
* _______ _ ______ _______ _______ ______ *
* ( ____ \( \ ( __ \ |\ /|( ___ )( )|\ /|( __ \ *
* | ( \/| ( | ( \ )| ) ( || ( ) || () () || ) ( || ( \ ) *
* | (__ | | | | ) || (___) || (___) || || || || | | || | ) | *
* | __) | | | | | || ___ || ___ || |(_)| || | | || | | | *
* | ( | | | | ) || ( ) || ( ) || | | || | | || | ) | *
* | (____/\| (____/\| (__/ )| ) ( || ) ( || ) ( || (___) || (__/ ) *
* (_______/(_______/(______/ |/ \||/ \||/ \|(_______)(______/ *
* +-+-+-+ +-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+ *
* |T|h|e| |O|a|k|l|a|n|d| |C|h|r|o|n|i|c|l|e|s| *
* +-+-+-+ +-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+ *
* ------------------------------------------------------------------------- *
* EldhaMUD code (C) 2003-2005 by Robert Powell (Tommi) *
* EldhaMUD Team: Celest, Altere and Krelowyn *
* ------------------------------------------------------------------------- *
* *
****************************************************************************/
/*****************************************************
** _________ __ **
** \_ ___ \_____|__| _____ ________ ___ **
** / \ \/_ __ \ |/ \/ ___/_ \/ \ **
** \ \___| | \/ | | | \___ \ / ) | \ **
** \______ /__| |__|__|_| /____ \__/__| / **
** ____\/____ _ \/ ___ \/ \/ **
** \______ \ |_____ __| _/___ **
** | | _/ |\__ \/ __ | __ \ **
** | | \ |_/ __ \ / | ___/_ **
** |_____ /__/____ /_ /___ / **
** \/Antipode\/ \/ \/ **
******************************************************
******************************************************
** Copyright 2000-2003 Crimson Blade **
******************************************************
** Contributors: Noplex, Krowe, Emberlyna, Lanthos **
******************************************************/
/****************************************************************************
* Version History *
****************************************************************************
* (v1.0) - Liquidtable converted into linked list, original 15 Smaug liqs *
* now read from a .dat file in /system *
* (v1.5) - OLC support added to create, edit, and delete liquids while *
* the game is still running, automatic edit. *
* (v2.0) - Mixture support code added. Liquids can now be mixed with *
* other liquids to form a result. *
* (v2.2) - Liquid statistics command added (liquids) shows all information*
* about the given liquid. *
* (v2.3) - OLC addition for mixtures. *
* (v2.4) - Mixtures are now saved into a seperate file and one linked list*
* because of some saving and loading issues. All the code has *
* been modified to accept the new format. "liq_can_mix" function *
* introduced. "mix" command introduced to mix liquids. *
* (v2.5) - Thanks to Samson for some polishing and bugfixing, we now have *
* a (hopefully) fully funcitonal copy =). *
* (v2.6) - "Fill" and "Empty" functions have been fixed to allow for the *
* new liquidsystem. *
* (v2.7) - Forgot to fix blood support... fixed. *
* - IS_VAMPIRE ifcheck placed in do_drink *
* - Blood fix for blood on the ground. *
* - do_look/do_exam fix from Sirek. *
* (v2.8) - Ability to mix objects into liquids. *
* (original code/concept -Sirek) *
* (v2.9) - Added in checks to make sure you are adding valid vnums to a *
* mixture. Changed display of mixture to show names and vnums *
* of components. Added in a manual save and an updated help file*
****************************************************************************/
/*
* File: liquids.c
* Name: Liquidtable Module (3.0b)
* 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 "./Headers/mud.h"
#ifdef KEY
#undef KEY
#endif /*
*/
#define KEY( literal, field, value ) \
if ( !str_cmp( word, literal ) ) \
{ \
field = value; \
fMatch = TRUE; \
break; \
}
#ifndef NULLSTR
#define NULLSTR(str) (!str || str[0] == '\0')
#endif /*
*/
/* globals */
LIQ_TABLE * liquid_table[MAX_LIQUIDS];
MIX_TABLE * first_mixture;
MIX_TABLE * last_mixture;
const char *liquid_types[LIQTYPE_TOP] =
{
"Beverage", "Alcohol", "Poison", "Unused"
};
char *const mod_types[MAX_CONDS] =
{
"Drunk", "Full", "Thirst"
};
/* locals */
int top_liquid;
int liq_count;
int file_version;
bool file_old;
/* 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;
snprintf( filename, 256, "%sliquids.dat", SYSTEM_DIR );
if( !( fp = fopen( filename, "w" ) ) )
{
bug( "save_liquids(): cannot open %s for writing", filename );
return;
}
fprintf( fp, "%s", "#VERSION 3\n" );
for( i = 0; i < top_liquid; i++ )
{
if( !liquid_table[i] )
continue;
liq = liquid_table[i];
fprintf( fp, "%s", "#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\n", liq->mod[COND_DRUNK], liq->mod[COND_FULL], liq->mod[COND_THIRST] );
fprintf( fp, "%s", "End\n\n" );
}
fprintf( fp, "%s", "#END\n" );
fclose( fp );
fp = NULL;
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->vnum = -1;
liq->type = -1;
for( i = 0; i < MAX_CONDS; i++ )
liq->mod[i] = -1;
for( ;; )
{
const 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 );
if( file_version < 3 )
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( "%s: no match for %s", __FUNCTION__, word );
fread_to_eol( fp );
}
}
}
/* load the liquids from the liquidtable.dat file in the system directory -Nopey */
void load_liquids( void )
{
FILE * fp = NULL;
char filename[256];
file_version = 0;
snprintf( filename, 256, "%sliquids.dat", SYSTEM_DIR );
if( !( fp = fopen( filename, "r" ) ) )
{
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 );
if( !liq )
bug( "%s", "load_liquids(): returned NULL liquid" );
else
{
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 );
fp = NULL;
return;
}
/* save the mixtures to the mixture table -Nopey */
void save_mixtures( void )
{
MIX_TABLE * mix = NULL;
FILE * fp = NULL;
char filename[256];
snprintf( filename, 256, "%smixtures.dat", SYSTEM_DIR );
if( !( fp = fopen( filename, "w" ) ) )
{
bug( "save_mixtures(): cannot open %s for writing", filename );
return;
}
fprintf( fp, "%s", "#VERSION 3\n" );
for( mix = first_mixture; mix; mix = mix->next )
{
fprintf( fp, "%s", "#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, "%s", "End\n" );
}
fprintf( fp, "%s", "#END\n" );
fclose( fp );
fp = NULL;
return;
}
/* read the mixtures into the structure -Nopey */
MIX_TABLE * fread_mixture( FILE * fp )
{
MIX_TABLE * mix = NULL;
bool fMatch = FALSE;
CREATE( mix, MIX_TABLE, 1 );
mix->data[0] = -1;
mix->data[1] = -1;
mix->data[2] = -1;
mix->object = FALSE;
for( ;; )
{
const 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" ) )
{
return mix;
}
break;
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;
case 'W':
if( !str_cmp( word, "With" ) )
{
mix->data[0] = fread_number( fp );
mix->data[1] = fread_number( fp );
}
break;
}
if( !fMatch )
{
bug( "%s: no match for %s", __FUNCTION__, word );
fread_to_eol( fp );
}
}
}
/* load the mixtures from the mixture table -Nopey */
void load_mixtures( void )
{
FILE * fp = NULL;
char filename[256];
file_version = 0;
snprintf( filename, 256, "%smixtures.dat", SYSTEM_DIR );
if( !( fp = fopen( filename, "r" ) ) )
{
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_version = fread_number( fp );
continue;
}
else if( !str_cmp( word, "MIXTURE" ) )
{
MIX_TABLE * mix = NULL;
mix = fread_mixture( fp );
if( !mix )
bug( "%s", "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 );
fp = NULL;
return;
}
/* 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;
}
/* Function to display liquid list. - Tarl 9 Jan 03 */
void do_showliquid( CHAR_DATA * ch, char *argument )
{
LIQ_TABLE * liq = NULL;
int i;
if( !IS_IMMORTAL( ch ) || IS_NPC( ch ) )
{
send_to_char( "Huh?\n\r", ch );
return;
}
if( !NULLSTR( argument ) && ( ( liq = get_liq( argument ) ) != NULL ) )
{
if( !NULLSTR( liq->name ) )
pager_printf( ch, "&GLiquid information for:&g %s\n\r", liq->name );
if( !NULLSTR( liq->shortdesc ) )
pager_printf( ch, "&GLiquid shortdesc:&g\t %s\n\r", liq->shortdesc );
if( !NULLSTR( liq->color ) )
pager_printf( ch, "&GLiquid color:&g\t %s\n\r", liq->color );
pager_printf( ch, "&GLiquid vnum:&g\t %d\n\r", liq->vnum );
pager_printf( ch, "&GLiquid type:&g\t %s\n\r", liquid_types[liq->type] );
send_to_pager( "&GLiquid Modifiers\n\r", ch );
for( i = 0; i < MAX_CONDS; i++ )
if( liquid_table[i] )
pager_printf( 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 'showliquid' to gain a vaild liquidvnum.\n\r", ch );
return;
}
send_to_pager( "&G[&gVnum&G] [&gName&G]\n\r", ch );
send_to_pager( "-------------------------\n\r", ch );
for( i = 0; i <= top_liquid; i++ )
{
if( !liquid_table[i] )
continue;
pager_printf( ch, " %-7d %s\n\r", liquid_table[i]->vnum, liquid_table[i]->name );
}
send_to_pager( "\n\rUse 'showliquid [vnum]' to view individual liquids.\n\r", ch );
send_to_pager( "Use 'showmixture' to view the mixturetable.\n\r", ch );
return;
}
/* olc function for liquids -Nopey */
void do_setliquid( CHAR_DATA * ch, char *argument )
{
char arg[MIL];
if( !IS_IMMORTAL( ch ) || IS_NPC( ch ) )
{
send_to_char( "Huh?\n\r", ch );
return;
}
smash_tilde( argument );
argument = one_argument( argument, arg );
if( NULLSTR( arg ) )
{
send_to_char( "Syntax: setliquid <vnum> <field> <value>\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, "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->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;
if( NULLSTR( argument ) )
{
send_to_char( "Syntax: setliquid delete <vnum>\n\r", ch );
return;
}
if( !is_number( argument ) )
{
if( !( liq = get_liq( argument ) ) )
{
send_to_char( "No such liquid type. Use 'showliquid' to get a valid list.\n\r", ch );
return;
}
}
else
{
int i = atoi( argument );
if( !( liq = get_liq_vnum( i ) ) )
{
send_to_char( "No such vnum. Use 'showliquid' to get the vnum.\n\r", ch );
return;
}
}
STRFREE( liq->name );
STRFREE( liq->color );
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.. Liquids saved.\n\r", ch );
save_liquids( );
return;
}
else
{
char arg2[MIL];
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;
}
STRFREE( liq->name );
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;
}
STRFREE( liq->color );
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;
}
STRFREE( liq->shortdesc );
liq->shortdesc = STRALLOC( argument );
}
else if( !str_cmp( arg2, "type" ) )
{
char arg3[MIL];
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" };
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;
}
}
void displaymixture( CHAR_DATA * ch, MIX_TABLE * mix )
{
send_to_pager( " .-. ,\n\r", ch );
send_to_pager( "`._ ,\n\r", ch );
send_to_pager( " \\ \\ o\n\r", ch );
send_to_pager( " \\ `-,.\n\r", ch );
send_to_pager( " .'o . `.[] o\n\r", ch );
send_to_pager( "<~- - , ,[].'.[] ~> ___\n\r", ch );
send_to_pager( " : : (-~.)\n\r", ch );
send_to_pager( " ` ' `|'\n\r", ch );
send_to_pager( " ` ' |\n\r", ch );
send_to_pager( " `-. .-' |\n\r", ch );
send_to_pager( "-----{. _ _ .}-------------------\n\r", ch );
pager_printf( ch, "&gRecipe for Mixture &G%s&g:\n\r", mix->name );
send_to_pager( "---------------------------------\n\r", ch );
if( !mix->object ) /*this is an object */
{
LIQ_TABLE * ingred1 = get_liq_vnum( mix->data[0] );
LIQ_TABLE * ingred2 = get_liq_vnum( mix->data[1] );
send_to_pager( "&wCombine two liquids to create this mixture:\n\r", ch );
if( !ingred1 )
{
pager_printf( ch, "Vnum1 (%d) is invalid, tell an Admin\n\r", mix->data[0] );
}
else
{
pager_printf( ch, "&wOne part &G%s&w (%d)\n\r", ingred1->name, mix->data[0] );
}
if( !ingred2 )
{
pager_printf( ch, "Vnum2 (%d) is invalid, tell an Admin\n\r", mix->data[1] );
}
else
{
pager_printf( ch, "&wAnd part &G%s&w (%d)&D\n\r", ingred2->name, mix->data[1] );
}
}
else
{
OBJ_INDEX_DATA * obj = get_obj_index( mix->data[0] );
if( !obj )
{
pager_printf( ch, "%s has a bad object vnum %d, inform an Admin\n\r", mix->name, mix->data[0] );
return;
}
else
{
LIQ_TABLE * ingred1 = get_liq_vnum( mix->data[1] );
send_to_pager( "Combine an object and a liquid in this mixture\n\r", ch );
pager_printf( ch, "&wMix &G%s&w (%d)\n\r", obj->name, mix->data[0] );
pager_printf( ch, "&winto one part &G%s&w (%d)&D\n\r", ingred1->name, mix->data[1] );
}
}
return;
}
/* Function for showmixture - Tarl 9 Jan 03 */
void do_showmixture( CHAR_DATA * ch, char *argument )
{
MIX_TABLE * mix = NULL;
if( !IS_IMMORTAL( ch ) || IS_NPC( ch ) )
{
send_to_char( "Huh?\n\r", ch );
return;
}
if( !NULLSTR( argument ) && ( ( mix = get_mix( argument ) ) != NULL ) )
{
displaymixture( ch, mix );
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 are currently no mixtures loaded.\n\r", ch );
return;
}
send_to_pager( "&G[&gType&G] &G[&gName&G]\n\r", ch );
send_to_pager( "-----------------------\n\r", ch );
for( mix = first_mixture; mix; mix = mix->next )
pager_printf( ch, " %-12s &g%s&D\n\r", mix->object ? "&PObject&D" : "&BLiquid&D", mix->name );
send_to_pager( "\n\r&gUse 'showmixture [name]' to view individual mixtures.\n\r", ch );
send_to_pager( "&gUse 'showliquid' to view the liquidtable.\n\r&d", ch );
return;
}
/* olc funciton for mixtures -Nopey */
void do_setmixture( CHAR_DATA * ch, char *argument )
{
char arg[MIL];
LIQ_TABLE * liq = NULL;
if( !IS_IMMORTAL( ch ) || IS_NPC( ch ) )
{
send_to_char( "Huh?\n\r", ch );
return;
}
smash_tilde( argument );
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 save - (saves table)\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 ) )
{
displaymixture( ch, mix );
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 are currently no mixtures loaded.\n\r", ch );
return;
}
send_to_pager( "&G[&gType&G] &G[&gName&G]\n\r", ch );
send_to_pager( "-----------------------\n\r", ch );
for( mix = first_mixture; mix; mix = mix->next )
pager_printf( ch, " %-12s &g%s&D\n\r", mix->object ? "&PObject&D" : "&BLiquid&D", mix->name );
send_to_pager( "\n\r&gUse 'showmixture [name]' to view individual mixtures.\n\r", ch );
send_to_pager( "&gUse 'showliquid' to view the liquidtable.&d\n\r", ch );
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, "save" ) )
{
save_mixtures( );
send_to_char( "Mixture table saved.\n\r", ch );
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 );
STRFREE( mix->name );
DISPOSE( mix );
send_to_char( "Done.\n\r", ch );
save_mixtures( );
return;
}
else
{
char arg2[MIL];
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;
}
STRFREE( mix->name );
mix->name = STRALLOC( argument );
}
else if( !str_cmp( arg2, "vnum1" ) )
{
int i = 0;
if( is_number( argument ) )
{
i = atoi( argument );
}
else
{
send_to_char( "Invalid liquid vnum.\n\r", ch );
send_to_char( "Syntax: setmixture <mixname> vnum1 <liqvnum or objvnum>\n\r", ch );
return;
}
if( mix->object == TRUE )
{
OBJ_INDEX_DATA * obj = get_obj_index( i );
if( !obj )
{
ch_printf( ch, "Invalid object vnum %d\n\r", i );
return;
}
else
{
mix->data[0] = i;
ch_printf( ch, "Mixture object set to %d - %s\n\r", i, obj->name );
}
}
else
{
liq = get_liq_vnum( i );
if( !liq )
{
ch_printf( ch, "Liquid vnum %d does not exist\n\r", i );
return;
}
else
{
mix->data[0] = i;
ch_printf( ch, "Mixture Vnum1 set to %s \n\r", liq->name );
}
}
}
else if( !str_cmp( arg2, "vnum2" ) )
{
int i = 0;
if( is_number( argument ) )
{
i = atoi( argument );
}
else
{
send_to_char( "Invalid liquid vnum.\n\r", ch );
send_to_char( "Syntax: setmixture <mixname> vnum2 <liqvnum>\n\r", ch );
return;
}
/*
* Verify liq exists
*/
liq = get_liq_vnum( i );
if( !liq )
{
ch_printf( ch, "Liquid vnum %d does not exist\n\r", i );
return;
}
else
{
mix->data[1] = i;
ch_printf( ch, "Mixture Vnum2 set to %s \n\r", liq->name );
}
}
else if( !str_cmp( arg2, "object" ) )
{
if( mix->object == FALSE )
{
mix->object = TRUE;
send_to_char( "Mixture -vnum1- is now an object-vnum.\n\r", ch );
}
else
{
mix->object = FALSE;
send_to_char( "Both mixture vnums are now liquids.\n\r", ch );
}
}
else if( !str_cmp( arg2, "into" ) )
{
int i;
if( is_number( argument ) )
{
i = atoi( argument );
}
else
{
send_to_char( "Invalid liquid vnum.\n\r", ch );
send_to_char( "Syntax: setmixture <mixname> into <liqvnum>\n\r", ch );
return;
}
liq = get_liq_vnum( i );
if( !liq )
{
ch_printf( ch, "Liquid vnum %d does not exist\n\r", i );
return;
}
else
{
mix->data[2] = i;
ch_printf( ch, "Mixture will now turn into %s \n\r", liq->name );
}
}
send_to_char( "Done.. Saving Mixtures.\n\r", ch );
save_mixtures( );
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;
separate_obj( iObj );
obj_from_char( iObj );
extract_obj( iObj );
return liq;
}
}
return NULL;
}
/* the actual -mix- funciton -Nopey */
void do_mix( CHAR_DATA * ch, char *argument )
{
char arg[MIL];
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( "&cYou mix them together.&g\n\r", ch );
return;
}
/* modified do_drink function -Nopey */
void do_drink( CHAR_DATA * ch, char *argument )
{
char arg[MIL];
OBJ_DATA * obj;
AFFECT_DATA af;
int amount;
bool immuneH = FALSE, immuneT = FALSE;
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] > 40 )
{
send_to_char( "You fail to reach your mouth. *Hic*\n\r", ch );
return;
}
if( !IS_NPC( ch ) )
{
if( ch->pcdata->condition[COND_THIRST] == -1 )
immuneT = TRUE;
if( ch->pcdata->condition[COND_FULL] == -1 )
immuneH = TRUE;
}
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:
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 )
{
char buf[MIL];
snprintf( buf, MIL, "quaff %s", obj->name );
do_quaff( ch, buf );
}
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] = 100;
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] );
}
else if( !IS_NPC( ch ) && obj->value[2] == 0 )
ch->pcdata->condition[COND_THIRST] = 100;
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
*/
if( !IS_NPC( ch ) && ( ch->pcdata->condition[COND_THIRST] == 100
||ch->pcdata->condition[COND_FULL] == 100 ) )
{
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( 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] > 50 && ch->pcdata->condition[COND_DRUNK] < 40 )
send_to_char( "You feel quite sloshed.\n\r", ch );
else if( ch->pcdata->condition[COND_DRUNK] >= 40 && ch->pcdata->condition[COND_DRUNK] < 60 )
send_to_char( "You start to feel a little drunk.\n\r", ch );
else if( ch->pcdata->condition[COND_DRUNK] >= 60 && ch->pcdata->condition[COND_DRUNK] < 90 )
send_to_char( "Your vision starts to get blurry.\n\r", ch );
else if( ch->pcdata->condition[COND_DRUNK] >= 90 && ch->pcdata->condition[COND_DRUNK] < 100 )
send_to_char( "You feel very drunk.\n\r", ch );
else if( ch->pcdata->condition[COND_DRUNK] == 100 )
send_to_char( "You feel like your going to pass out.\n\r", ch );
if( ch->pcdata->condition[COND_THIRST] > 50 && ch->pcdata->condition[COND_THIRST] < 40 )
send_to_char( "Your stomach begins to slosh around.\n\r", ch );
else if( ch->pcdata->condition[COND_THIRST] >= 40 && ch->pcdata->condition[COND_THIRST] < 60 )
send_to_char( "You start to feel bloated.\n\r", ch );
else if( ch->pcdata->condition[COND_THIRST] >= 60 && ch->pcdata->condition[COND_THIRST] < 90 )
send_to_char( "You feel bloated.\n\r", ch );
else if( ch->pcdata->condition[COND_THIRST] >= 90 && ch->pcdata->condition[COND_THIRST] < 100 )
send_to_char( "You stomach is almost filled to it's brim!\n\r", ch );
else if( ch->pcdata->condition[COND_THIRST] == 100 )
send_to_char( "Your stomach is full, you can't manage to get anymore down.\n\r", ch );
}
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 );
}
break;
}
}
if( !IS_NPC( ch ) )
{
if( immuneH )
ch->pcdata->condition[COND_FULL] = -1;
if( immuneT )
ch->pcdata->condition[COND_THIRST] = -1;
}
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[MIL], arg2[MIL];
OBJ_DATA * obj;
OBJ_DATA * source;
short 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
{
if( 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;
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[MIL];
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 );
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[MIL], 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 || 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 || arg2[0] == '\0' )
{
if( xIS_SET( ch->in_room->room_flags, ROOM_NODROP ) || xIS_SET( ch->act, PLR_LITTERBUG ) )
{
send_to_char( "&[magic]A magical force stops you!\n\r", ch );
send_to_char( "&[tell]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;
}
}
void free_liquiddata( void )
{
MIX_TABLE * mix, *mix_next;
LIQ_TABLE * liq;
int loopa;
for( mix = first_mixture; mix; mix = mix_next )
{
mix_next = mix->next;
UNLINK( mix, first_mixture, last_mixture, next, prev );
STRFREE( mix->name );
DISPOSE( mix );
}
for( loopa = 0; loopa <= top_liquid; loopa++ )
{
liq = get_liq_vnum( loopa );
STRFREE( liq->name );
STRFREE( liq->color );
STRFREE( liq->shortdesc );
DISPOSE( liq );
}
return;
}