1stMud4.5.3/
1stMud4.5.3/backup/
1stMud4.5.3/bin/
1stMud4.5.3/bin/extras/
1stMud4.5.3/data/i3/
1stMud4.5.3/doc/1stMud/
1stMud4.5.3/doc/Diku/
1stMud4.5.3/doc/MPDocs/
1stMud4.5.3/doc/Rom/
1stMud4.5.3/notes/
/**************************************************************************
*  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
*  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
*                                                                         *
*  Merc Diku Mud improvements 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          *
*  benefiting.  We hope that you share your changes too.  What goes       *
*  around, comes around.                                                  *
***************************************************************************
*       ROM 2.4 is copyright 1993-1998 Russ Taylor                        *
*       ROM has been brought to you by the ROM consortium                 *
*           Russ Taylor (rtaylor@hypercube.org)                           *
*           Gabrielle Taylor (gtaylor@hypercube.org)                      *
*           Brian Moore (zump@rom.org)                                    *
*       By using this code, you have agreed to follow the terms of the    *
*       ROM license, in the file Rom24/doc/rom.license                    *
***************************************************************************
*          1stMud ROM Derivative (c) 2001-2004 by Markanth                *
*            http://www.firstmud.com/  <markanth@firstmud.com>            *
*         By using this code you have agreed to follow the term of        *
*             the 1stMud license in ../doc/1stMud/LICENSE                 *
***************************************************************************/

#include "merc.h"
#include "recycle.h"

void acid_effect(void *vo, int level, int dam, int target)
{
	if (target == TARGET_ROOM)
	{
		RoomIndex *room = (RoomIndex *) vo;
		ObjData *obj, *obj_next;

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

	if (target == TARGET_CHAR)
	{
		CharData *victim = (CharData *) vo;
		ObjData *obj, *obj_next;

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

	if (target == TARGET_OBJ)
	{
		ObjData *obj = (ObjData *) vo;
		ObjData *t_obj, *n_obj;
		int chance;
		char *msg;

		if (IsObjStat(obj, ITEM_BURN_PROOF) || IsObjStat(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 (IsObjStat(obj, ITEM_BLESS))
			chance -= 5;

		chance -= obj->level * 2;

		switch (obj->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 = Range(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->person_first != NULL)
			act(msg, obj->in_room->person_first, obj, NULL, TO_ALL);

		if (obj->item_type == ITEM_ARMOR)
		{
			AffectData *paf;
			bool af_found = false;
			int i;

			affect_enchant(obj);

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

			if (!af_found)

			{
				paf = new_affect();

				paf->type = -1;
				paf->level = level;
				paf->duration = -1;
				paf->location = APPLY_AC;
				paf->modifier = 1;
				paf->bitvector = 0;
				Link(paf, obj->affect, next, prev);
			}

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

		if (obj->content_first)
		{
			for (t_obj = obj->content_first; 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);
					continue;
				}

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

		extract_obj(obj);
		return;
	}
}

void cold_effect(void *vo, int level, int dam, int target)
{
	if (target == TARGET_ROOM)
	{
		RoomIndex *room = (RoomIndex *) vo;
		ObjData *obj, *obj_next;

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

	if (target == TARGET_CHAR)
	{
		CharData *victim = (CharData *) vo;
		ObjData *obj, *obj_next;

		if (!saves_spell(level / 4 + dam / 20, victim, DAM_COLD))
		{
			AffectData 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 = skill_lookup("chill touch");
			af.level = level;
			af.duration = 6;
			af.location = APPLY_STR;
			af.modifier = -1;
			af.bitvector = 0;
			affect_join(victim, &af);
		}

		if (!IsNPC(victim))
			gain_condition(victim, COND_HUNGER, dam / 20);

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

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

		if (IsObjStat(obj, ITEM_BURN_PROOF) || IsObjStat(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 (IsObjStat(obj, ITEM_BLESS))
			chance -= 5;

		chance -= obj->level * 2;

		switch (obj->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 = Range(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->person_first != NULL)
			act(msg, obj->in_room->person_first, obj, NULL, TO_ALL);

		extract_obj(obj);
		return;
	}
}

void fire_effect(void *vo, int level, int dam, int target)
{
	if (target == TARGET_ROOM)
	{
		RoomIndex *room = (RoomIndex *) vo;
		ObjData *obj, *obj_next;

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

	if (target == TARGET_CHAR)
	{
		CharData *victim = (CharData *) vo;
		ObjData *obj, *obj_next;

		if (!IsAffected(victim, AFF_BLIND)
			&& !saves_spell(level / 4 + dam / 20, victim, DAM_FIRE))
		{
			AffectData 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 = skill_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);
		}

		if (!IsNPC(victim))
			gain_condition(victim, COND_THIRST, dam / 20);

		for (obj = victim->carrying_first; obj != NULL; obj = obj_next)
		{
			obj_next = obj->next_content;

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

	if (target == TARGET_OBJ)
	{
		ObjData *obj = (ObjData *) vo;
		ObjData *t_obj, *n_obj;
		int chance;
		char *msg;

		if (IsObjStat(obj, ITEM_BURN_PROOF) || IsObjStat(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 (IsObjStat(obj, ITEM_BLESS))
			chance -= 5;
		chance -= obj->level * 2;

		switch (obj->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 = Range(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->person_first != NULL)
			act(msg, obj->in_room->person_first, obj, NULL, TO_ALL);

		if (obj->content_first)
		{

			for (t_obj = obj->content_first; 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);
					continue;
				}
				fire_effect(t_obj, level / 2, dam / 2, TARGET_OBJ);
			}
		}

		extract_obj(obj);
		return;
	}
}

void poison_effect(void *vo, int level, int dam, int target)
{
	if (target == TARGET_ROOM)
	{
		RoomIndex *room = (RoomIndex *) vo;
		ObjData *obj, *obj_next;

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

	if (target == TARGET_CHAR)
	{
		CharData *victim = (CharData *) vo;
		ObjData *obj, *obj_next;

		if (!saves_spell(level / 4 + dam / 20, victim, DAM_POISON))
		{
			AffectData af;

			chprintln(victim, "You feel poison coursing through your veins.");
			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);
		}

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

	if (target == TARGET_OBJ)
	{
		ObjData *obj = (ObjData *) vo;
		int chance;

		if (IsObjStat(obj, ITEM_BURN_PROOF) || IsObjStat(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->item_type)
		{
			default:
				return;
			case ITEM_FOOD:
				break;
			case ITEM_DRINK_CON:
				if (obj->value[0] == obj->value[1])
					return;
				break;
		}

		chance = Range(5, chance, 95);

		if (number_percent() > chance)
			return;

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

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

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

	if (target == TARGET_CHAR)
	{
		CharData *victim = (CharData *) vo;
		ObjData *obj, *obj_next;

		if (!saves_spell(level / 4 + dam / 20, victim, DAM_LIGHTNING))
		{
			chprintln(victim, "Your muscles stop responding.");
			DazeState(victim, Max(12, level / 4 + dam / 20));
		}

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

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

		if (IsObjStat(obj, ITEM_BURN_PROOF) || IsObjStat(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 (IsObjStat(obj, ITEM_BLESS))
			chance -= 5;

		chance -= obj->level * 2;

		switch (obj->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 = Range(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->person_first != NULL)
			act(msg, obj->in_room->person_first, obj, NULL, TO_ALL);

		extract_obj(obj);
		return;
	}
}