zim/area/
zim/bin/
zim/clans/plists/
zim/corefiles/
zim/doc/muddy/
zim/gods/
zim/log/
zim/player/
zim/skill_tree/
zim/tmp/
/*
 * $Id: effects.c 932 2006-11-11 00:07:22Z zsuzsu $
 */

/***************************************************************************
 *     ANATOLIA 2.1 is copyright 1996-1997 Serdar BULUT, Ibrahim CANPUNAR  *
 *     ANATOLIA has been brought to you by ANATOLIA consortium		   *
 *	 Serdar BULUT {Chronos}		bulut@rorqual.cc.metu.edu.tr       *
 *	 Ibrahim Canpunar  {Asena}	canpunar@rorqual.cc.metu.edu.tr    *	
 *	 Murat BICER  {KIO}		mbicer@rorqual.cc.metu.edu.tr	   *	
 *	 D.Baris ACAR {Powerman}	dbacar@rorqual.cc.metu.edu.tr	   *	
 *     By using this code, you have agreed to follow the terms of the      *
 *     ANATOLIA license, in the file Anatolia/anatolia.licence             *	
 ***************************************************************************/

/***************************************************************************
 *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
 *  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
 *                                                                         *
 *  Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael          *
 *  Chastain, Michael Quan, and Mitchell Tse.                              *
 *                                                                         *
 *  In order to use any part of this Merc Diku Mud, you must comply with   *
 *  both the original Diku license in 'license.doc' as well the Merc       *
 *  license in 'license.txt'.  In particular, you may not remove either of *
 *  these copyright notices.                                               *
 *                                                                         *
 *  Much time and thought has gone into this software and you are          *
 *  benefitting.  We hope that you share your changes too.  What goes      *
 *  around, comes around.                                                  *
 ***************************************************************************/

/***************************************************************************
*	ROM 2.4 is copyright 1993-1995 Russ Taylor			   *
*	ROM has been brought to you by the ROM consortium		   *
*	    Russ Taylor (rtaylor@pacinfo.com)				   *
*	    Gabrielle Taylor (gtaylor@pacinfo.com)			   *
*	    Brian Moore (rom@rom.efn.org)				   *
*	By using this code, you have agreed to follow the terms of the	   *
*	ROM license, in the file Rom24/doc/rom.license			   *
***************************************************************************/

#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "merc.h"
#include "debug.h"
#include "update.h"

void acid_effect(void *vo, int level, int dam, int target)
{
	if (target == TARGET_ROOM) {	/* nail objects on the floor */
		ROOM_INDEX_DATA *room = (ROOM_INDEX_DATA *) vo;
		OBJ_DATA *obj, *obj_next;

		for (obj = room->contents; obj != NULL; obj = obj_next) {
			obj_next = obj->next_content;
			acid_effect(obj, level, dam, TARGET_OBJ);
		}
		return;
	}

	if (target == TARGET_CHAR) {	/* do the effect on a victim */
		CHAR_DATA *victim = (CHAR_DATA *) vo;
		OBJ_DATA *obj, *obj_next;

		/* let's toast some gear */
		for (obj = victim->carrying; obj != NULL; obj = obj_next) {
			obj_next = obj->next_content;
			acid_effect(obj, level, dam, TARGET_OBJ);
		}
		return;
	}

	if (target == TARGET_OBJ) {	/* toast an object */
		OBJ_DATA *obj = (OBJ_DATA *) vo;
		OBJ_DATA *t_obj, *n_obj;
		int chance;
		char *msg;

		if (IS_OBJ_STAT(obj, ITEM_BURN_PROOF)
		    || IS_OBJ_STAT(obj, ITEM_NOPURGE)
		    || number_range(0, 4) == 0)
			return;

		chance = level / 4 + dam / 10;

		if (chance > 25)
			chance = (chance - 25) / 2 + 25;
		if (chance > 50)
			chance = (chance - 50) / 2 + 50;

		if (IS_OBJ_STAT(obj, ITEM_BLESS))
			chance -= 5;

		chance -= obj->level * 2;

		switch (obj->pIndexData->item_type) {
		default:
			return;
		case ITEM_CONTAINER:
		case ITEM_CORPSE_PC:
		case ITEM_CORPSE_NPC:
			msg = "$p fumes and dissolves.";
			break;
		case ITEM_ARMOR:
			msg = "$p is pitted and etched.";
			break;
		case ITEM_CLOTHING:
			msg = "$p is corroded into scrap.";
			break;
		case ITEM_STAFF:
		case ITEM_WAND:
			chance -= 10;
			msg = "$p corrodes and breaks.";
			break;
		case ITEM_SCROLL:
			chance += 10;
			msg = "$p is burned into waste.";
			break;
		}

		chance = URANGE(5, chance, 95);

		if (number_percent() > chance)
			return;

		if (obj->carried_by != NULL)
			act(msg, obj->carried_by, obj, NULL, TO_ALL);
		else if (obj->in_room != NULL && obj->in_room->people != NULL)
			act(msg, obj->in_room->people, obj, NULL, TO_ALL);

		if (obj->pIndexData->item_type == ITEM_ARMOR) {	/* etch it */
			AFFECT_DATA *paf;
			bool af_found = FALSE;
			int i;

			affect_enchant(obj);

			for (paf = obj->affected; paf != NULL; paf = paf->next) {
				if (paf->location == APPLY_AC) {
					af_found = TRUE;
					paf->type = -1;
					paf->modifier += 1;
					paf->level = UMAX(paf->level, level);
					break;
				}
			}

			if (!af_found)
				/* needs a new affect */
			{
				paf = aff_new();

				paf->type = -1;
				paf->level = level;
				paf->duration = -1;
				paf->location = APPLY_AC;
				paf->modifier = 1;
				paf->bitvector = 0;
				paf->next = obj->affected;
				obj->affected = paf;
			}

			if (obj->carried_by != NULL
			    && obj->wear_loc != WEAR_NONE)
				for (i = 0; i < 4; i++)
					obj->carried_by->armor[i] += 1;
			return;
		}

		/* get rid of the object */
		if (obj->contains) {	/* dump contents */
			for (t_obj = obj->contains; t_obj != NULL;
			     t_obj = n_obj) {
				n_obj = t_obj->next_content;
				obj_from_obj(t_obj);
				if (obj->in_room != NULL)
					obj_to_room(t_obj, obj->in_room);
				else if (obj->carried_by != NULL)
					obj_to_room(t_obj,
						    obj->carried_by->in_room);
				else {
					extract_obj(t_obj, 0);
					continue;
				}

				acid_effect(t_obj, level / 2, dam / 2,
					    TARGET_OBJ);
			}
		}

		extract_obj(obj, 0);
		return;
	}
}


void cold_effect(void *vo, int level, int dam, int target)
{
	if (target == TARGET_ROOM) {	/* nail objects on the floor */
		ROOM_INDEX_DATA *room = (ROOM_INDEX_DATA *) vo;
		OBJ_DATA *obj, *obj_next;

		for (obj = room->contents; obj != NULL; obj = obj_next) {
			obj_next = obj->next_content;
			cold_effect(obj, level, dam, TARGET_OBJ);
		}
		return;
	}

	if (target == TARGET_CHAR) {	/* whack a character */
		CHAR_DATA *victim = (CHAR_DATA *) vo;
		OBJ_DATA *obj, *obj_next;

		/* chill touch effect */
		if (!saves_spell(level / 4 + dam / 20, victim, DAM_COLD)) {
			AFFECT_DATA af;

			act("$n turns blue and shivers.", victim, NULL, NULL,
			    TO_ROOM);
			act("A chill sinks deep into your bones.", victim, NULL,
			    NULL, TO_CHAR);
			af.where = TO_AFFECTS;
			af.type = sn_lookup("chill touch");
			af.level = level;
			af.duration = 6;
			af.location = APPLY_STR;
			af.modifier = -1;
			af.bitvector = 0;
			affect_join(victim, &af);
		}

		/* hunger! (warmth sucked out */
		if (!IS_NPC(victim))
			gain_condition(victim, COND_HUNGER, dam / 20);

		/* let's toast some gear */
		for (obj = victim->carrying; obj != NULL; obj = obj_next) {
			obj_next = obj->next_content;
			cold_effect(obj, level, dam, TARGET_OBJ);
		}
		return;
	}

	if (target == TARGET_OBJ) {	/* toast an object */
		OBJ_DATA *obj = (OBJ_DATA *) vo;
		int chance;
		char *msg;

		if (IS_OBJ_STAT(obj, ITEM_BURN_PROOF)
		    || IS_OBJ_STAT(obj, ITEM_NOPURGE)
		    || number_range(0, 4) == 0)
			return;

		chance = level / 4 + dam / 10;

		if (chance > 25)
			chance = (chance - 25) / 2 + 25;
		if (chance > 50)
			chance = (chance - 50) / 2 + 50;

		if (IS_OBJ_STAT(obj, ITEM_BLESS))
			chance -= 5;

		chance -= obj->level * 2;

		switch (obj->pIndexData->item_type) {
		default:
			return;
		case ITEM_POTION:
			msg = "$p freezes and shatters!";
			chance += 25;
			break;
		case ITEM_DRINK_CON:
			msg = "$p freezes and shatters!";
			chance += 5;
			break;
		}

		chance = URANGE(5, chance, 95);

		if (number_percent() > chance)
			return;

		if (obj->carried_by != NULL)
			act(msg, obj->carried_by, obj, NULL, TO_ALL);
		else if (obj->in_room != NULL && obj->in_room->people != NULL)
			act(msg, obj->in_room->people, obj, NULL, TO_ALL);

		extract_obj(obj, 0);
		return;
	}
}



void fire_effect(void *vo, int level, int dam, int target)
{

	if (target == TARGET_ROOM) {	/* nail objects on the floor */
		ROOM_INDEX_DATA *room = (ROOM_INDEX_DATA *) vo;
		OBJ_DATA *obj, *obj_next;
		for (obj = room->contents; obj != NULL; obj = obj_next) {
			obj_next = obj->next_content;
			fire_effect(obj, level, dam, TARGET_OBJ);
		}
		return;
	}

	if (target == TARGET_CHAR) {	/* do the effect on a victim */
		CHAR_DATA *victim = (CHAR_DATA *) vo;
		OBJ_DATA *obj, *obj_next;

		/* chance of blindness */
		if (!IS_AFFECTED(victim, AFF_BLIND)
		    && !saves_spell(level / 4 + dam / 20, victim, DAM_FIRE)) {
			AFFECT_DATA af;
			act("$n is blinded by smoke!", victim, NULL, NULL,
			    TO_ROOM);
			act("Your eyes tear up from smoke...you can't see a thing!", victim, NULL, NULL, TO_CHAR);

			af.where = TO_AFFECTS;
			af.type = sn_lookup("fire breath");
			af.level = level;
			af.duration = number_range(0, level / 10);
			af.location = APPLY_HITROLL;
			af.modifier = -4;
			af.bitvector = AFF_BLIND;

			affect_to_char(victim, &af);
		}

		/* getting thirsty */
		if (!IS_NPC(victim))
			gain_condition(victim, COND_THIRST, dam / 20);

		/* let's toast some gear! */
		for (obj = victim->carrying; obj != NULL; obj = obj_next) {
			obj_next = obj->next_content;

			fire_effect(obj, level, dam, TARGET_OBJ);
		}
		return;
	}

	if (target == TARGET_OBJ) {	/* toast an object */
		OBJ_DATA *obj = (OBJ_DATA *) vo;
		OBJ_DATA *t_obj, *n_obj;
		int chance;
		char *msg;

		if (IS_OBJ_STAT(obj, ITEM_BURN_PROOF)
		    || IS_OBJ_STAT(obj, ITEM_NOPURGE)
		    || number_range(0, 4) == 0)
			return;

		chance = level / 4 + dam / 10;

		if (chance > 25)
			chance = (chance - 25) / 2 + 25;
		if (chance > 50)
			chance = (chance - 50) / 2 + 50;

		if (IS_OBJ_STAT(obj, ITEM_BLESS))
			chance -= 5;
		chance -= obj->level * 2;

		if (check_material(obj, "ice")) {
			chance += 30;
			msg = "$p melts and evaporates!";
		} else
			switch (obj->pIndexData->item_type) {
			default:
				return;
			case ITEM_CONTAINER:
				msg = "$p ignites and burns!";
				break;
			case ITEM_POTION:
				chance += 25;
				msg = "$p bubbles and boils!";
				break;
			case ITEM_SCROLL:
				chance += 50;
				msg = "$p crackles and burns!";
				break;
			case ITEM_STAFF:
				chance += 10;
				msg = "$p smokes and chars!";
				break;
			case ITEM_WAND:
				msg = "$p sparks and sputters!";
				break;
			case ITEM_FOOD:
				msg = "$p blackens and crisps!";
				break;
			case ITEM_PILL:
				msg = "$p melts and drips!";
				break;
			}

		chance = URANGE(5, chance, 95);

		if (number_percent() > chance)
			return;

		if (obj->carried_by != NULL)
			act(msg, obj->carried_by, obj, NULL, TO_ALL);
		else if (obj->in_room != NULL && obj->in_room->people != NULL)
			act(msg, obj->in_room->people, obj, NULL, TO_ALL);

		if (obj->contains) {
			/* dump the contents */

			for (t_obj = obj->contains; t_obj != NULL;
			     t_obj = n_obj) {
				n_obj = t_obj->next_content;
				obj_from_obj(t_obj);
				if (obj->in_room != NULL)
					obj_to_room(t_obj, obj->in_room);
				else if (obj->carried_by != NULL)
					obj_to_room(t_obj,
						    obj->carried_by->in_room);
				else {
					extract_obj(t_obj, 0);
					continue;
				}
				fire_effect(t_obj, level / 2, dam / 2,
					    TARGET_OBJ);
			}
		}

		extract_obj(obj, 0);
		return;
	}
}

void poison_effect(void *vo, int level, int dam, int target)
{
	if (target == TARGET_ROOM) {	/* nail objects on the floor */
		ROOM_INDEX_DATA *room = (ROOM_INDEX_DATA *) vo;
		OBJ_DATA *obj, *obj_next;

		for (obj = room->contents; obj != NULL; obj = obj_next) {
			obj_next = obj->next_content;
			poison_effect(obj, level, dam, TARGET_OBJ);
		}
		return;
	}

	if (target == TARGET_CHAR) {	/* do the effect on a victim */
		CHAR_DATA *victim = (CHAR_DATA *) vo;
		OBJ_DATA *obj, *obj_next;

		/* chance of poisoning */
		if (!saves_spell(level / 4 + dam / 20, victim, DAM_POISON)) {
			AFFECT_DATA af;

			char_puts
			    ("You feel poison coursing through your veins.\n",
			     victim);
			act("$n looks very ill.", victim, NULL, NULL, TO_ROOM);

			af.where = TO_AFFECTS;
			af.type = gsn_poison;
			af.level = level;
			af.duration = level / 2;
			af.location = APPLY_STR;
			af.modifier = -1;
			af.bitvector = AFF_POISON;
			affect_join(victim, &af);
		}

		/* equipment */
		for (obj = victim->carrying; obj != NULL; obj = obj_next) {
			obj_next = obj->next_content;
			poison_effect(obj, level, dam, TARGET_OBJ);
		}
		return;
	}

	if (target == TARGET_OBJ) {	/* do some poisoning */
		OBJ_DATA *obj = (OBJ_DATA *) vo;
		int chance;


		if (IS_OBJ_STAT(obj, ITEM_BURN_PROOF)
		    || IS_OBJ_STAT(obj, ITEM_BLESS)
		    || number_range(0, 4) == 0)
			return;

		chance = level / 4 + dam / 10;
		if (chance > 25)
			chance = (chance - 25) / 2 + 25;
		if (chance > 50)
			chance = (chance - 50) / 2 + 50;

		chance -= obj->level * 2;

		switch (obj->pIndexData->item_type) {
		default:
			return;
		case ITEM_FOOD:
			break;
		case ITEM_DRINK_CON:
			if (obj->value[ITEM_DRINK_TOTAL] == obj->value[ITEM_DRINK_REMAINING])
				return;
			break;
		}

		chance = URANGE(5, chance, 95);

		if (number_percent() > chance)
			return;

		obj->value[ITEM_FOOD_POISON] = 1;
		return;
	}
}


void shock_effect(void *vo, int level, int dam, int target)
{
	if (target == TARGET_ROOM) {
		ROOM_INDEX_DATA *room = (ROOM_INDEX_DATA *) vo;
		OBJ_DATA *obj, *obj_next;

		for (obj = room->contents; obj != NULL; obj = obj_next) {
			obj_next = obj->next_content;
			shock_effect(obj, level, dam, TARGET_OBJ);
		}
		return;
	}

	if (target == TARGET_CHAR) {
		CHAR_DATA *victim = (CHAR_DATA *) vo;
		OBJ_DATA *obj, *obj_next;

		/* daze and confused? */
		if (!saves_spell(level / 4 + dam / 20, victim, DAM_LIGHTNING)) {
			char_puts("Your muscles stop responding.\n", victim);
			DAZE_STATE(victim, UMAX(12, level / 4 + dam / 20));
		}

		/* toast some gear */
		for (obj = victim->carrying; obj != NULL; obj = obj_next) {
			obj_next = obj->next_content;
			shock_effect(obj, level, dam, TARGET_OBJ);
		}
		return;
	}

	if (target == TARGET_OBJ) {
		OBJ_DATA *obj = (OBJ_DATA *) vo;
		int chance;
		char *msg;

		if (IS_OBJ_STAT(obj, ITEM_BURN_PROOF)
		    || IS_OBJ_STAT(obj, ITEM_NOPURGE)
		    || number_range(0, 4) == 0)
			return;

		chance = level / 4 + dam / 10;

		if (chance > 25)
			chance = (chance - 25) / 2 + 25;
		if (chance > 50)
			chance = (chance - 50) / 2 + 50;

		if (IS_OBJ_STAT(obj, ITEM_BLESS))
			chance -= 5;

		chance -= obj->level * 2;

		switch (obj->pIndexData->item_type) {
		default:
			return;
		case ITEM_WAND:
		case ITEM_STAFF:
			chance += 10;
			msg = "$p overloads and explodes!";
			break;
		case ITEM_JEWELRY:
			chance -= 10;
			msg = "$p is fused into a worthless lump.";
		}

		chance = URANGE(5, chance, 95);

		if (number_percent() > chance)
			return;

		if (obj->carried_by != NULL)
			act(msg, obj->carried_by, obj, NULL, TO_ALL);
		else if (obj->in_room != NULL && obj->in_room->people != NULL)
			act(msg, obj->in_room->people, obj, NULL, TO_ALL);

		extract_obj(obj, 0);
		return;
	}
}

void sand_effect(void *vo, int level, int dam, int target)
{
	if (target == TARGET_ROOM) {	/* nail objects on the floor */
		ROOM_INDEX_DATA *room = (ROOM_INDEX_DATA *) vo;
		OBJ_DATA *obj, *obj_next;

		for (obj = room->contents; obj != NULL; obj = obj_next) {
			obj_next = obj->next_content;
			sand_effect(obj, level, dam, TARGET_OBJ);
		}
		return;
	}

	if (target == TARGET_CHAR) {	/* do the effect on a victim */
		CHAR_DATA *victim = (CHAR_DATA *) vo;
		OBJ_DATA *obj, *obj_next;

		if (!IS_AFFECTED(victim, AFF_BLIND)
		    && !saves_spell(level / 4 + dam / 20, victim, DAM_COLD)) {
			AFFECT_DATA af;
			act("$n is blinded by flying sands!", victim, NULL,
			    NULL, TO_ROOM);
			act("Your eyes tear up from sands...you can't see a thing!", victim, NULL, NULL, TO_CHAR);

			af.where = TO_AFFECTS;
			af.type = sn_lookup("sand storm");
			af.level = level;
			af.duration = number_range(0, level / 10);
			af.location = APPLY_HITROLL;
			af.modifier = -4;
			af.bitvector = AFF_BLIND;

			affect_to_char(victim, &af);
		}

		/* let's toast some gear */
		for (obj = victim->carrying; obj != NULL; obj = obj_next) {
			obj_next = obj->next_content;
			sand_effect(obj, level, dam, TARGET_OBJ);
		}
		return;
	}

	if (target == TARGET_OBJ) {	/* toast an object */
		OBJ_DATA *obj = (OBJ_DATA *) vo;
		OBJ_DATA *t_obj, *n_obj;
		int chance;
		char *msg;

		if (IS_OBJ_STAT(obj, ITEM_BURN_PROOF)
		    || IS_OBJ_STAT(obj, ITEM_NOPURGE)
		    || number_range(0, 4) == 0)
			return;

		chance = level / 4 + dam / 10;

		if (chance > 25)
			chance = (chance - 25) / 2 + 25;
		if (chance > 50)
			chance = (chance - 50) / 2 + 50;

		if (IS_OBJ_STAT(obj, ITEM_BLESS))
			chance -= 5;

		chance -= obj->level * 2;

		switch (obj->pIndexData->item_type) {
		default:
			return;
		case ITEM_CONTAINER:
		case ITEM_CORPSE_PC:
		case ITEM_CORPSE_NPC:
			chance += 50;
			msg = "$p is filled with sand and evaporates.";
			break;
		case ITEM_ARMOR:
			chance -= 10;
			msg = "$p is etched by sand.";
			break;
		case ITEM_CLOTHING:
			msg = "$p is corroded by sands.";
			break;
		case ITEM_WAND:
			chance = 50;
			msg = "$p mixes with crashing sands.";
			break;
		case ITEM_SCROLL:
			chance += 20;
			msg = "$p is surrouned by sand.";
			break;
		case ITEM_POTION:
			chance += 10;
			msg = "$p is broken into pieces by crashing sands.";
			break;
		}

		chance = URANGE(5, chance, 95);

		if (number_percent() > chance)
			return;

		if (obj->carried_by != NULL)
			act(msg, obj->carried_by, obj, NULL, TO_ALL);
		else if (obj->in_room != NULL && obj->in_room->people != NULL)
			act(msg, obj->in_room->people, obj, NULL, TO_ALL);

		if (obj->pIndexData->item_type == ITEM_ARMOR) {	/* etch it */
			AFFECT_DATA *paf;
			bool af_found = FALSE;
			int i;

			affect_enchant(obj);

			for (paf = obj->affected; paf != NULL; paf = paf->next) {
				if (paf->location == APPLY_AC) {
					af_found = TRUE;
					paf->type = -1;
					paf->modifier += 1;
					paf->level = UMAX(paf->level, level);
					break;
				}
			}

			if (!af_found)
				/* needs a new affect */
			{
				paf = aff_new();

				paf->type = -1;
				paf->level = level;
				paf->duration = level;
				paf->location = APPLY_AC;
				paf->modifier = 1;
				paf->bitvector = 0;
				paf->next = obj->affected;
				obj->affected = paf;
			}

			if (obj->carried_by != NULL
			    && obj->wear_loc != WEAR_NONE)
				for (i = 0; i < 4; i++)
					obj->carried_by->armor[i] += 1;
			return;
		}

		/* get rid of the object */
		if (obj->contains) {	/* dump contents */
			for (t_obj = obj->contains; t_obj != NULL;
			     t_obj = n_obj) {
				n_obj = t_obj->next_content;
				obj_from_obj(t_obj);
				if (obj->in_room != NULL)
					obj_to_room(t_obj, obj->in_room);
				else if (obj->carried_by != NULL)
					obj_to_room(t_obj,
						    obj->carried_by->in_room);
				else {
					extract_obj(t_obj, 0);
					continue;
				}

				sand_effect(t_obj, level / 2, dam / 2,
					    TARGET_OBJ);
			}
		}

		extract_obj(obj, 0);
		return;
	}
}

void scream_effect(void *vo, int level, int dam, int target)
{

	if (target == TARGET_ROOM) {	/* nail objects on the floor */
		ROOM_INDEX_DATA *room = (ROOM_INDEX_DATA *) vo;
		OBJ_DATA *obj, *obj_next;
		for (obj = room->contents; obj != NULL; obj = obj_next) {
			obj_next = obj->next_content;
			scream_effect(obj, level, dam, TARGET_OBJ);
		}
		return;
	}

	if (target == TARGET_CHAR) {	/* do the effect on a victim */
		CHAR_DATA *victim = (CHAR_DATA *) vo;
		OBJ_DATA *obj, *obj_next;

		if (!saves_spell(level / 4 + dam / 20, victim, DAM_SOUND)) {
			AFFECT_DATA af;
			act("$n can't hear anything!", victim, NULL, NULL,
			    TO_ROOM);
			act("You can't hear a thing!", victim, NULL, NULL,
			    TO_CHAR);

			af.where = TO_AFFECTS;
			af.type = gsn_scream;
			af.level = level;
			af.duration = 0;
			af.location = APPLY_NONE;
			af.modifier = 0;
			af.bitvector = AFF_SCREAM;

			affect_to_char(victim, &af);
		}

		/* daze and confused? */
		if (!saves_spell(level / 4 + dam / 20, victim, DAM_SOUND)) {
			char_puts("You can't hear anything!.\n", victim);
			DAZE_STATE(victim, UMAX(12, level / 4 + dam / 20));
		}


		/* getting thirsty */
		if (!IS_NPC(victim))
			gain_condition(victim, COND_THIRST, dam / 20);

		/* let's toast some gear! */
		for (obj = victim->carrying; obj != NULL; obj = obj_next) {
			obj_next = obj->next_content;

			scream_effect(obj, level, dam, TARGET_OBJ);
		}
		return;
	}

	if (target == TARGET_OBJ) {	/* toast an object */
		OBJ_DATA *obj = (OBJ_DATA *) vo;
		OBJ_DATA *t_obj, *n_obj;
		int chance;
		char *msg;

		if (IS_OBJ_STAT(obj, ITEM_BURN_PROOF)
		    || IS_OBJ_STAT(obj, ITEM_NOPURGE)
		    || number_range(0, 4) == 0)
			return;

		chance = level / 4 + dam / 10;

		if (chance > 25)
			chance = (chance - 25) / 2 + 25;
		if (chance > 50)
			chance = (chance - 50) / 2 + 50;

		if (IS_OBJ_STAT(obj, ITEM_BLESS))
			chance -= 5;
		chance -= obj->level * 2;

		if (check_material(obj, "ice")) {
			chance += 30;
			msg = "$p breaks and evaporates!";
		} else if (check_material(obj, "glass")) {
			chance += 30;
			msg = "$p breaks into tiny small pieces.";
		} else
			switch (obj->pIndexData->item_type) {
			default:
				return;
			case ITEM_POTION:
				chance += 25;
				msg = "Vial of $p breaks and liquid spoils!";
				break;
			case ITEM_SCROLL:
				chance += 50;
				msg = "$p breaks into tiny pieces!";
				break;
			case ITEM_DRINK_CON:
				msg = "$p breaks and liquid spoils!";
				chance += 5;
				break;
			case ITEM_PILL:
				msg = "$p breaks into pieces!";
				break;
			}

		chance = URANGE(5, chance, 95);

		if (number_percent() > chance)
			return;

		if (obj->carried_by != NULL)
			act(msg, obj->carried_by, obj, NULL, TO_ALL);
		else if (obj->in_room != NULL && obj->in_room->people != NULL)
			act(msg, obj->in_room->people, obj, NULL, TO_ALL);

		if (obj->contains) {
			/* dump the contents */

			for (t_obj = obj->contains; t_obj != NULL;
			     t_obj = n_obj) {
				n_obj = t_obj->next_content;
				obj_from_obj(t_obj);
				if (obj->in_room != NULL)
					obj_to_room(t_obj, obj->in_room);
				else if (obj->carried_by != NULL)
					obj_to_room(t_obj,
						    obj->carried_by->in_room);
				else {
					extract_obj(t_obj, 0);
					continue;
				}
				scream_effect(t_obj, level / 2, dam / 2,
					      TARGET_OBJ);
			}
		}

		extract_obj(obj, 0);
		return;
	}
}

/*
 * Add or Remove the Intoxication affect
 *
 * This effect checks the skill "drinking".
 * The better the skill, the more beneficial
 * and the less detrimental the effect will
 * be to the character.
 *
 * returns FALSE if they are already drunk
 *               or if they are alread sober
 *
 * by Zsuzsu
 */
bool drunk_effect(CHAR_DATA * ch, int level, bool intoxicate)
{
	AFFECT_DATA af;
	int sn = -1;
	int chance = 0;
	int hitroll, damroll, ac, saves, str, dex;

	sn = gsn_drinking;
	chance = get_skill(ch, sn);

	if (intoxicate && is_affected(ch, gsn_intoxication))
		return FALSE;
	if (!intoxicate && !is_affected(ch, gsn_intoxication))
		return FALSE;

	if (intoxicate) {
		hitroll = -1 * (level / 10 + number_range(5, 15));
		damroll = level / 10 + number_range(5, 15);
		ac = level + 10 + number_range(0, level / 4);
		saves = UMIN(-1, (-1 * level / 10)
			     + number_range(-3, 3));
		str = 2;
		dex = -4;

		if (chance > 1) {
			hitroll += number_fuzzy((hitroll / 2) *
						((chance) / 100));
			damroll +=
			    number_fuzzy((damroll / 3) * ((chance) / 100));
			ac -= number_fuzzy((ac / 4) * (chance / 100));

			if (number_percent() < chance) {
				saves -= number_range(0, 2);
				dex = -3;
			}
		}

		if (!IS_NPC(ch))
			DEBUG(DEBUG_SKILL_DRINKING,
				"drunk: %s[%d] "
				"%d/+%d +%dac %dsave +%dstr %ddex",
				ch->name, level,
				hitroll, damroll, ac, saves, str, dex);

		af.where = TO_AFFECTS;
		af.type = gsn_intoxication;
		af.level = level;
		af.duration = IS_NPC(ch) ? level / 20 + 1 : -1;
		af.bitvector = 0;

		af.location = APPLY_DEX;
		af.modifier = dex;
		affect_to_char(ch, &af);

		af.location = APPLY_STR;
		af.modifier = str;
		affect_to_char(ch, &af);

		/* god protects fools and drunks */
		af.location = APPLY_SAVES;
		af.modifier = saves;
		affect_to_char(ch, &af);

		af.location = APPLY_AC;
		af.modifier = ac;
		affect_to_char(ch, &af);

		af.location = APPLY_DAMROLL;
		af.modifier = damroll;
		affect_to_char(ch, &af);

		af.location = APPLY_HITROLL;
		af.modifier = hitroll;
		affect_to_char(ch, &af);

		act("$n looks three sheets to the wind.",
		    ch, NULL, NULL, TO_ROOM);
		char_puts("The room starts to spin.\n", ch);

		check_improve(ch, gsn_drinking, TRUE, 1);
	}

	/* remove drunk effect */
	else {
		affect_strip(ch, gsn_intoxication);
		act("$n looks less dizzy.", ch, NULL, NULL, TO_ROOM);
		char_puts("You feel less dizzy.\n", ch);
	}

	return TRUE;
}