
/***************************************************************************
*       FALLEN ANGELS mud is protected by french law of intelectual        *
*                            property. we share freely that code           *
*                            provided this message isn't removed from the  *
*                            files and you respect the name of all the     *
*                            coders,area builders, and all the Diku,Merc,  *
*                            Rom licences.                                 *
*                                                                          *
*                   Thank to : ROM consortium .                            *
*                   Big thank to : Gary Gygax !!!!!!!!!!!!!!               *
*                                                                          *
*       Fallen Angel project by : Loran      ( laurent zilber  )           *
*                                 Silfen or                                *
*                                 Gwendoline ( jerome despret  )           *
*                                                                          *
*       despret@ecoledoc.lip6.fr ...                                       *
***************************************************************************/

/***************************************************************************
*                                                                          *
*  To use this snipet you must set the following line in the "check" help  *
*                                                                          *
*    Coded for Fallen Angels by : Zilber laurent,Despret jerome.           *
*                                                                          *
*  And send a mail to say you use it ( feel free to comment ) at :         *
*                                                                          *
*  [despret@ecoledoc.lip6.fr] or/and at [lzilber@hotmail.com]              *
****************************************************************************/

/***************************************************************************
*                                                                          *
* If you want to put this snipet on your web site you are allowed to but   *
*  the file must remain unchanged and you have to send us a mail at :      *
*                                                                          *
*  [despret@ecoledoc.lip6.fr] or/and at [lzilber@hotmail.com]              *
*  with the site URL.                                                      *
*                                                                          *
***************************************************************************/

/* -------  INSTALATION PROCEDURE ---------------------------------

   In file "act_obj.c" replace the following function by those ones :
    do_drink, do_pour, do_fill

   Copy the "auto_quaff" function in handler.c, and add the following
   line in "merc.h" around line 2390 after : /* handler.c */ 

    bool auto_quaff               args( ( CHAR_DATA *ch, OBJ_DATA *obj ) );
     
   Ok all is done now ... it should work... please if you have any problem
   write us.
---------------------------------------------------------------------*/


/***************************************************************************

   This code allow players to fill some drink_containers with potions.
   A container can hold as many potions as they could formerly hold
   drink. 
   You can drink once from it per potion you pour into it.
   You can't mix various potion into a same container.
   A container have to be empty to accept potions into it.
   If you fill a container with a standart liquid you waste any potion
   inside.

   Finally, it only work for standart potion ( found in any area ) not for
   some weird potion some mud allow players to create themself. If it is
   your case, just forbid such potion to be used with pour.

   Be very carrefull for balance to not create Burn_proof drink container
   and to set a standart wait_state for the drink command.

    syntax : pour <potion> <container> 

   example :
              pour waterskin out
              pour potion waterskin

***************************************************************************/

/* replace in act_obj.c */

void do_fill( CHAR_DATA *ch, char *argument )
{
    char arg[MAX_INPUT_LENGTH];
    char buf[MAX_STRING_LENGTH];
    OBJ_DATA *obj;
    OBJ_DATA *fountain;
    bool found;

    one_argument( argument, arg );

    if ( arg[0] == '\0' )
    {
	send_to_char( "Fill what?\n\r", ch );
	return;
    }

    if ( ( obj = get_obj_carry( ch, arg, ch ) ) == NULL )
    {
	send_to_char( "You do not have that item.\n\r", ch );
	return;
    }

    found = FALSE;
    for ( fountain = ch->in_room->contents; fountain != NULL;
	fountain = fountain->next_content )
    {
	if ( fountain->item_type == ITEM_FOUNTAIN )
	{
	    found = TRUE;
	    break;
	}
    }

    if ( !found )
    {
	send_to_char( "There is no fountain here!\n\r", ch );
	return;
    }

    if ( obj->item_type != ITEM_DRINK_CON )
    {
	send_to_char( "You can't fill that.\n\r", ch );
	return;
    }

    if ( obj->value[1] != 0 && obj->value[2] != fountain->value[2] )
    {
	send_to_char( "There is already another liquid in it.\n\r", ch );
	return;
    }

    if ( obj->value[1] >= obj->value[0] )
    {
	send_to_char( "Your container is full.\n\r", ch );
	return;
    }

    sprintf(buf,"You fill $p with %s from $P.",
	liq_table[fountain->value[2]].liq_name);
    act( buf, ch, obj,fountain, TO_CHAR );
    sprintf(buf,"$n fills $p with %s from $P.",
	liq_table[fountain->value[2]].liq_name);
    act(buf,ch,obj,fountain,TO_ROOM);
    obj->value[2] = fountain->value[2];
    obj->value[1] = obj->value[0];
    obj->value[4] = 0; /* jerome : potion filling security fix */
    return;
}

void do_pour (CHAR_DATA *ch, char *argument)
{
    char arg[MAX_STRING_LENGTH],buf[MAX_STRING_LENGTH];
    OBJ_DATA *out, *in;
    CHAR_DATA *vch = NULL;
    int amount,dose=0;
    bool potion = FALSE;

    argument = one_argument(argument,arg);
    
    if (arg[0] == '\0' || argument[0] == '\0')
    {
	send_to_char("Pour what into what?\n\r",ch);
	return;
    }
    

    if ((out = get_obj_carry(ch,arg, ch)) == NULL)
    {
	send_to_char("You don't have that item.\n\r",ch);
	return;
    }

    if ( out->item_type == ITEM_POTION ) potion = TRUE;

    if ( (out->item_type != ITEM_DRINK_CON) && (!potion) )
    {
	send_to_char("That's not a drink container or a potion.\n\r",ch);
	return;
    }

    if (!str_cmp(argument,"out"))
    {
	if (out->value[1] == 0)
	{
	    send_to_char("It's already empty.\n\r",ch);
	    return;
	}

	out->value[1] = 0;
	out->value[3] = 0;
        if(  out->value[4] != 0 )potion = TRUE;
        out->value[4] = 0;

        if( !potion )
        {
    	  sprintf(buf,"You invert $p, spilling %s all over the ground.",
		liq_table[out->value[2]].liq_name);
	  act(buf,ch,out,NULL,TO_CHAR);
	
	  sprintf(buf,"$n inverts $p, spilling %s all over the ground.",
		liq_table[out->value[2]].liq_name);
	  act(buf,ch,out,NULL,TO_ROOM);
        }
        else
        {
         act("You invert $p, spilling the magical liquid all over the ground.",
           ch,out,NULL,TO_CHAR);
         act("$n invert $p, spilling the magical liquid all over the ground.",
           ch,out,NULL,TO_ROOM);
        }
	return;
    }

    if ((in = get_obj_here(ch,argument)) == NULL)
    {
	vch = get_char_room(ch,argument);

	if (vch == NULL)
	{
	    send_to_char("Pour into what?\n\r",ch);
	    return;
	}

	in = get_eq_char(vch,WEAR_HOLD);

	if (in == NULL)
	{
	    send_to_char("They aren't holding anything.",ch);
 	    return;
	}
    }

    if (in->item_type != ITEM_DRINK_CON)
    {
	send_to_char("You can only pour into a drink containers.\n\r",ch);
	return;
    }
    
    if (in == out)
    {
	send_to_char("You cannot change the laws of physics!\n\r",ch);
	return;
    }

    if (   ( (!potion) && (in->value[1] != 0) 
                       && (in->value[2] != out->value[2]) )
         ||(  (potion) && (  ( (in->value[4] != 0 )  
                             &&(in->value[4] != out->pIndexData->vnum) ) 
                           ||( (in->value[1] != 0) 
                             &&(in->value[4] == 0) ) ) ) ) 
    {
	send_to_char("They don't hold the same liquid.\n\r",ch);
	return;
    }

    if ( (!potion) && (out->value[1] == 0) )
    {
	act("There's nothing in $p to pour.",ch,out,NULL,TO_CHAR);
	return;
    }

    if (in->value[1] >= in->value[0])
    {
	act("$p is already filled to the top.",ch,in,NULL,TO_CHAR);
	return;
    }
  
    if( potion )
    {
      dose = liq_table[ in->value[2] ].liq_affect[4];
      amount = UMIN( dose , in->value[0]  - dose );
      in->value[1] += amount;
      if( (in->value[4] != 0) && (in->value[4] != out->pIndexData->vnum ) )
        bug("Error potion mixing in pour command with potion %d",in->value[4]);
      in->value[4] = out->pIndexData->vnum;
      extract_obj( out );
    }
    else
    {
      amount = UMIN(out->value[1],in->value[0] - in->value[1]);
      in->value[1] += amount;
      out->value[1] -= amount;
      in->value[2] = out->value[2];
    } 

    if (vch == NULL)
    {
      if( !potion)
      {
    	sprintf(buf,"You pour %s from $p into $P.",
	    liq_table[out->value[2]].liq_name);
    	act(buf,ch,out,in,TO_CHAR);
    	sprintf(buf,"$n pours %s from $p into $P.",
	    liq_table[out->value[2]].liq_name);
    	act(buf,ch,out,in,TO_ROOM);
      }
      else
      {
        act("You pour $p into $P.",ch,out,in,TO_CHAR);
        act("$n pours $p into $P.",ch,out,in,TO_ROOM);
      }

    }
    else
    {
      if(!potion)
       {
        sprintf(buf,"You pour some %s for $N.",
            liq_table[out->value[2]].liq_name);
        act(buf,ch,NULL,vch,TO_CHAR);
	sprintf(buf,"$n pours you some %s.",
	    liq_table[out->value[2]].liq_name);
	act(buf,ch,NULL,vch,TO_VICT);
        sprintf(buf,"$n pours some %s for $N.",
            liq_table[out->value[2]].liq_name);
        act(buf,ch,NULL,vch,TO_NOTVICT);
       }
       else
       {
        act("You pour some potion for $N.",ch,NULL,vch,TO_CHAR);
        act("$n pours you some potion.",ch,NULL,vch,TO_VICT);
        act("$n pours some potion for $N.",ch,NULL,vch,TO_NOTVICT);
       }
	
    }
}

void do_drink( CHAR_DATA *ch, char *argument )
{
    char arg[MAX_INPUT_LENGTH];
    OBJ_DATA *obj,*potion;
    int amount;
    int liquid;
    bool split = FALSE;

    one_argument( argument, arg );

    if ( arg[0] == '\0' )
    {
	for ( obj = ch->in_room->contents; obj; obj = obj->next_content )
	{
	    if ( obj->item_type == ITEM_FOUNTAIN )
		break;
	}

	if ( obj == NULL )
	{
	    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 ( !IS_NPC(ch) && ch->pcdata->condition[COND_DRUNK] > 10 )
    {
	send_to_char( "You fail to reach your mouth.  *Hic*\n\r", ch );
	return;
    }

    switch ( obj->item_type )
    {
    default:
	send_to_char( "You can't drink from that.\n\r", ch );
	return;

    case ITEM_FOUNTAIN:
        if ( ( liquid = obj->value[2] )  < 0 )
        {
            bug( "Do_drink: bad liquid number %d.", liquid );
            liquid = obj->value[2] = 0;
        }
	amount = liq_table[liquid].liq_affect[4] * 3;
	break;

    case ITEM_DRINK_CON:
	if ( obj->value[1] <= 0 )
	{
	    send_to_char( "It is already empty.\n\r", ch );
	    return;
	}

	if ( ( liquid = obj->value[2] )  < 0 )
	{
	    bug( "Do_drink: bad liquid number %d.", liquid );
	    liquid = obj->value[2] = 0;
	}

        amount = liq_table[liquid].liq_affect[4];
        amount = UMIN(amount, obj->value[1]);
	break;
     }
    if (!IS_NPC(ch) && !IS_IMMORTAL(ch) 
    &&  ch->pcdata->condition[COND_FULL] > 45)
    {
	send_to_char("You're too full to drink more.\n\r",ch);
	return;
    }

    if( obj->value[4] != 0 )
    { /* we are drinking some potion stored in the container */
         potion = create_object( get_obj_index( obj->value[4]) , 0 );
         if( !auto_quaff(ch,potion) )
          {
            extract_obj(potion);
            split = TRUE;
          }
    }
    else
    {
      act( "$n drinks $T from $p.",
	ch, obj, liq_table[liquid].liq_name, TO_ROOM );
      act( "You drink $T from $p.",
  	ch, obj, liq_table[liquid].liq_name, TO_CHAR );

      gain_condition( ch, COND_DRUNK,
	amount * liq_table[liquid].liq_affect[COND_DRUNK] / 36 );
      gain_condition( ch, COND_FULL,
 	amount * liq_table[liquid].liq_affect[COND_FULL] / 4 );
      gain_condition( ch, COND_THIRST,
	amount * liq_table[liquid].liq_affect[COND_THIRST] / 10 );
      gain_condition(ch, COND_HUNGER,
	amount * liq_table[liquid].liq_affect[COND_HUNGER] / 2 );

      if ( !IS_NPC(ch) && ch->pcdata->condition[COND_DRUNK]  > 10 )
     	send_to_char( "You feel drunk.\n\r", ch );
      if ( !IS_NPC(ch) && ch->pcdata->condition[COND_FULL]   > 40 )
	send_to_char( "You are full.\n\r", ch );
      if ( !IS_NPC(ch) && ch->pcdata->condition[COND_THIRST] > 40 )
	send_to_char( "Your thirst is quenched.\n\r", ch );
    }
	
    if ( obj->value[3] != 0 )
    {
	/* The drink was poisoned ! */
	AFFECT_DATA af;

	act( "$n chokes and gags.", ch, NULL, NULL, TO_ROOM );
	send_to_char( "You choke and gag.\n\r", ch );
	af.where     = TO_AFFECTS;
	af.type      = gsn_poison;
	af.level	 = number_fuzzy(amount); 
	af.duration  = 3 * amount;
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bitvector = AFF_POISON;
	affect_join( ch, &af );
    }
	
    if ( (!split) && (obj->value[0] > 0) )
        obj->value[1] -= amount;

    if( obj->value[1] <= 0 )obj->value[4] = 0;

    WAIT_STATE( ch, PULSE_VIOLENCE );

    return;
}


/* in handler.c add the following function */

bool auto_quaff(CHAR_DATA *ch, OBJ_DATA *obj)
{
   int i,skill;

    if ( obj->item_type != ITEM_POTION )
    {
        bug("auto_quaff invalide item type %d",obj->item_type );
        return FALSE;
    }

    if (ch->level < obj->level)
    {
        send_to_char("This liquid is too powerful for you to drink.\n\r",ch);
        return FALSE;
    }

    if ( ( IS_OBJ_STAT(obj, ITEM_ANTI_EVIL)    && IS_EVIL(ch)    )
    ||   ( IS_OBJ_STAT(obj, ITEM_ANTI_GOOD)    && IS_GOOD(ch)    )
    ||   ( IS_OBJ_STAT(obj, ITEM_ANTI_NEUTRAL) && IS_NEUTRAL(ch) ) )
    {
        act( "You are burned by the liquid and you split it.", ch, NULL, NULL, TO_CHAR );
        act( "$n is burned by the liquid and split it.",  ch, NULL, NULL, TO_ROOM );
        return FALSE;
    }

   for(i=1;( i < 4) && (ch != NULL ) && (ch->position > POS_DEAD);i++)
     {
       if( obj->value[i] != 0 )
           obj_cast_spell(   obj->value[i],   obj->value[0], ch, ch, NULL );
      }
  extract_obj(obj);
  return TRUE;
}
