empiremud/cnf/
empiremud/doc/
empiremud/lib/boards/
empiremud/lib/etc/
empiremud/lib/misc/
empiremud/lib/plralias/F-J/
empiremud/lib/plralias/K-O/
empiremud/lib/plralias/P-T/
empiremud/lib/plralias/U-Z/
empiremud/lib/plrobjs/
empiremud/lib/plrobjs/F-J/
empiremud/lib/plrobjs/K-O/
empiremud/lib/plrobjs/P-T/
empiremud/lib/plrobjs/U-Z/
empiremud/lib/world/
empiremud/lib/world/mob/
empiremud/lib/world/obj/
empiremud/log/
/* ************************************************************************
*   File: limits.c                                       EmpireMUD AD 1.0 *
*  Usage: limits & gain funcs for HMV, exp, hunger/thirst, idle time      *
*                                                                         *
*  All rights reserved.  See license.doc for complete information.        *
*                                                                         *
*  Code base by Paul Clarke.  EmpireMUD Project, a tbgMUD Production.     *
*  Based upon CircleMUD 3.0, beta patch level 17, by Jeremy Elson.        *
*                                                                         *
*  Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University *
*  CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991.               *
************************************************************************ */

#include "conf.h"
#include "sysdep.h"

#include "structs.h"
#include "utils.h"
#include "comm.h"
#include "db.h"
#include "handler.h"
#include "interpreter.h"
#include "skills.h"
#include "empire.h"
#include "vnums.h"

extern int use_autowiz;
extern int min_wizlist_lev;

void Crash_rentsave(Creature ch);
void die(Creature ch);
void death_log(Creature ch, Creature killer, int type);


int graf(int age, int p0, int p1, int p2, int p3, int p4, int p5, int p6) {
	/*
	 * Ingenius bit of code, this
	 * When age < 15 return the value p0
	 * When age in 15..29 calculate the line between p1 & p2
	 * When age in 30..44 calculate the line between p2 & p3
	 * When age in 45..59 calculate the line between p3 & p4
	 * When age in 60..79 calculate the line between p4 & p5
	 * When age >= 80 return the value p6
	 */

	if (age < 15)
		return (p0);											/* < 15   */
	else if (age <= 29)
		return (int) (p1 + (((age - 15) * (p2 - p1)) / 15));	/* 15..29 */
	else if (age <= 44)
		return (int) (p2 + (((age - 30) * (p3 - p2)) / 15));	/* 30..44 */
	else if (age <= 59)
		return (int) (p3 + (((age - 45) * (p4 - p3)) / 15));	/* 45..59 */
	else if (age <= 79)
		return (int) (p4 + (((age - 60) * (p5 - p4)) / 20));	/* 60..79 */
	else
		return (p6);											/* >= 80 */
	}


/* move gain pr. game hour */
int move_gain(Creature ch) {
	int gain;

	if (IS_NPC(ch))
		gain = 10;
	else {
		gain = graf(age(ch)->year, 1, 2, 3, 3, 2, 2, 1);

		/* Position calculations    */
		switch (GET_POS(ch)) {
			case POS_SLEEPING:		gain += 4;			break;
			case POS_RESTING:		gain += 2;			break;
			case POS_SITTING:		gain += 1;			break;
			}

		gain += GET_MOVE_REGEN(ch);

		if (IS_WEREWOLF(ch) && (GET_MORPH(ch) != GET_BREED_FORM(ch) || GET_MORPH(ch) == MORPH_CRINOS))
			gain *= 2;

		if (ROOM_TYPE(ch->in_room) == RTYPE_BEDROOM)
			gain *= 1.5;


		if (GET_COND(ch, FULL) >= 700 || GET_COND(ch, THIRST) >= 360 || GET_COND(ch, TIRED) >= 315)
			gain /= 4;
		}

	return (gain);
	}



void set_title(Creature ch, char *title) {
	if (title == NULL)
		title = "the newbie";

	if (strlen(title) > MAX_TITLE_LENGTH)
		title[MAX_TITLE_LENGTH] = '\0';

	if (GET_TITLE(ch) != NULL)
		free(GET_TITLE(ch));

	if (*title != ':' && *title != ',' && *title != '-' && *title != ';' && *title != '~')
		sprintf(buf2, " %s", title);
	else
		strcpy(buf2, title);

	GET_TITLE(ch) = str_dup(buf2);
	}


void check_autowiz(Creature ch) {
	if (use_autowiz && GET_LEVEL(ch) >= LVL_GOD) {
		char buf[128];

		sprintf(buf, "nice ../bin/autowiz %d %s %d %s %d &", min_wizlist_lev, WIZLIST_FILE, LVL_GOD, GODLIST_FILE, (int) getpid());

		syslog(0, TRUE, "Initiating autowiz.");
		system(buf);
		}
	}


void gain_condition(Creature ch, int condition, int value) {
	extern bool gain_cond_messsage;
	bool intoxicated;

	if (IS_NPC(ch) || GET_COND(ch, condition) == -1)	/* No change */
		return;

	intoxicated = (GET_COND(ch, DRUNK) > 0);

	GET_COND(ch, condition) += value;

	GET_COND(ch, condition) = MAX(0, GET_COND(ch, condition));
	GET_COND(ch, condition) = MIN(750, GET_COND(ch, condition));

	if (PLR_FLAGGED(ch, PLR_WRITING) || !gain_cond_messsage)
		return;

	switch (condition) {
		case FULL:
			if (GET_COND(ch, condition) >= 600)
				msg_to_char(ch, "You are hungry.\r\n");
			return;
		case THIRST:
			if (GET_COND(ch, condition) >= 360)
				msg_to_char(ch, "You are thirsty.\r\n");
			return;
		case DRUNK:
			if (intoxicated && !GET_COND(ch, condition))
				msg_to_char(ch, "You are now sober.\r\n");
			return;

		//remove sleep
		/*case TIRED:
			if (GET_COND(ch, condition) >= 360)
				msg_to_char(ch, "You are exhausted.\r\n");
			return;*/

		default:
			break;
		}
	}


void check_idling(Creature ch) {
	extern int idle_rent_time;
	extern int idle_linkdead_rent_time;

	ch->char_specials.timer++;

	if ((ch->desc && ch->char_specials.timer > idle_rent_time) || (!ch->desc && ch->char_specials.timer > idle_linkdead_rent_time)) {
		if (ch->desc) {
			STATE(ch->desc) = CON_DISCONNECT;
			ch->desc->character = NULL;
			ch->desc = NULL;
			}

		Crash_rentsave(ch);
		SAVE_CHAR(ch);

		syslog(GET_INVIS_LEV(ch), TRUE, "%s force-rented and extracted (idle).", GET_NAME(ch));
		extract_char(ch);
		}
	}


void random_encounter(Creature ch) {
	Creature mob;
	int i;

	struct encounter_table {
		mob_vnum vnum;
		int sect;
		int chance;
		char *msg;
		} encounters[] = {
			{ SHARK,	SECT_OCEAN,		5,
				"$N lunges up from the water and attacks!" },

			{ -1, 0, 0, "\n" }
			};

	if (!ch->desc || FIGHTING(ch) || IS_GOD(ch) || IS_IMMORTAL(ch))
		return;

	if (AFF_FLAGGED(ch, AFF_FLY))
		return;

	for (i = 0; encounters[i].vnum != -1; i++)
		if (SECT(ch->in_room) == encounters[i].sect && number(1, 100) <= encounters[i].chance) {
			char_to_room((mob = read_mobile(encounters[i].vnum, VIRTUAL)), ch->in_room);
			act(encounters[i].msg, FALSE, ch, 0, mob, TO_CHAR | TO_ROOM);
			hit(mob, ch);
			}
	}


void enter_torpor(Creature ch, byte type) {
	if (IS_INJURED(ch, INJ_TORPOR))
		return;

	if (IS_VAMPIRE(ch)) {
		switch (type) {
			case 1:
				msg_to_char(ch, "You succumb to the beast, and fall into torpor!\r\n");
				break;
			case 2:
				msg_to_char(ch, "You fall into torpor!\r\n");
				break;
			default:
				msg_to_char(ch, "You run out of blood and fall into torpor!\r\n");
				break;
			}
		act("$n falls down, dead.", FALSE, ch, 0, 0, TO_ROOM);
		add_lore(ch, LORE_TORPOR, 0);
		SET_BIT(INJURY_FLAGS(ch), INJ_TORPOR);
		GET_POS(ch) = POS_SLEEPING;
		}
	else {
		if (type)
			msg_to_char(ch, "You fall over, dead!\r\n");
		else
			msg_to_char(ch, "You die from lack of blood!\r\n");
		act("$n falls down, dead.", FALSE, ch, 0, 0, TO_ROOM);
		death_log(ch, ch, TYPE_SUFFERING);
		add_lore(ch, LORE_DEATH, 0);
		die(ch);
		}
	}


void perform_noon_update(void) {
	void remove_lore(Creature ch, int type, long value);

	Creature ch;

	for (ch = character_list; ch; ch = ch->next) {

		/* learn to bathe, jeez! */
		if (!IS_NPC(ch) && !IS_GOD(ch) && !IS_IMMORTAL(ch) && !DSC_FLAGGED(ch, DSC_BITUMENOUS_FLESH))
			GET_DAYS_SINCE_BATHING(ch) = MIN(10, GET_DAYS_SINCE_BATHING(ch) + 1);

		/* Regain 1 willpower per day */
		if (GET_WILLPOWER(ch) < GET_MAX_WILLPOWER(ch))
			GET_WILLPOWER(ch) += 1;

		/* Bood handling */
		if (!IS_VAMPIRE(ch)) {
			if (GET_DAMAGE(ch) > 0)
				GET_DAMAGE(ch) -= 1;
			if (GET_POS(ch) < POS_SLEEPING)
				GET_POS(ch) = POS_RESTING;
			if (GET_BLOOD(ch) < GET_MAX_BLOOD(ch))
				GET_BLOOD(ch)++;
			if (IS_GHOUL(ch)) {
				GET_VAMP_BLOOD(ch) -= 1;
				/* werewolves go thru it faster */
				if (IS_WEREWOLF(ch) && GET_VAMP_BLOOD(ch) > 0)
					GET_VAMP_BLOOD(ch) -= 1;
				/* werewolves go thru it faster AGAIN */
				if (IS_WEREWOLF(ch) && GET_VAMP_BLOOD(ch) > 0)
					GET_VAMP_BLOOD(ch) -= 1;

				if (GET_BLOOD(ch) > GET_MAX_BLOOD(ch))
					GET_BLOOD(ch) = GET_MAX_BLOOD(ch);
				if (GET_VAMP_BLOOD(ch) == 0) {
					msg_to_char(ch, "As the vampiric vitae in your system depletes, you find yourself merely mortal once more.\r\n");
					REMOVE_BIT(PLR_FLAGS(ch), PLR_GHOUL);
					remove_lore(ch, LORE_MAKE_GHOUL, -1);
					}
				}
			update_pos(ch);
			}
		else if (!DSC_FLAGGED(ch, DSC_BITUMENOUS_FLESH)) {
			if (GET_BLOOD(ch) > 0)
				GET_BLOOD(ch) -= 1;

			/* Additional point for eternal vigilance */
			if (GET_FORTITUDE(ch) >= 8 && GET_BLOOD(ch) > 0 && GET_POS(ch) > POS_SLEEPING)
				GET_BLOOD(ch) -= 1;

			/* Torpor */
			if (GET_BLOOD(ch) <= 0) {
				enter_torpor(ch, 0);
				continue;
				}
			}

		/* For all characters, aggravated damage goes down 1 per day */
		if (GET_AGG_DAMAGE(ch) > 0)
			GET_AGG_DAMAGE(ch) -= 1;
		}
	}


void real_update(void) {
	extern struct time_info_data time_info;
	ACMD(do_wake);
	extern int exp_cycle;
	void name(Creature ch, char *argument);

	Descr d;
	Creature ch;
	Object j;
	room_rnum room;
	byte dam;

	/* PC-only move regen update (and quit timer), done every 5 seconds */
	for (d = descriptor_list; d; d = d->next) {
		if (STATE(d) != CON_PLAYING || !(ch = d->character))
			continue;

		if (IS_VAMPIRE(ch)) {
			GET_COND(ch, FULL) = -1;
			GET_COND(ch, THIRST) = -1;
			GET_COND(ch, DRUNK) = -1;
			GET_COND(ch, TIRED) = -1;
			}

		/* Make sure people are not tired */
		GET_COND(ch, TIRED) = -1;


		if (IS_WEREWOLF(ch) && (GET_MORPH(ch) != GET_BREED_FORM(ch) || GET_MORPH(ch) == MORPH_CRINOS)) {
			if (GET_DAMAGE(ch) > GET_AGG_DAMAGE(ch) && GET_DAMAGE(ch) > 0)
				GET_DAMAGE(ch) -= 1;
			if (GET_DAMAGE(ch) < 7 && GET_POS(ch) < POS_SLEEPING)
				GET_POS(ch) = POS_RESTING;
			}

		/* Check this here */
		if (GET_ACADEMICS(ch) > 0)
			SET_BIT(GET_LANGUAGES(ch), LANGUAGE_BIT(LANG_LATIN));
		if (GET_ANIMALISM(ch) > 0 || IS_WEREWOLF(ch))
			SET_BIT(GET_LANGUAGES(ch), LANGUAGE_BIT(LANG_FERAL_SPEECH));
		if (IS_WEREWOLF(ch))
			SET_BIT(GET_LANGUAGES(ch), LANGUAGE_BIT(LANG_HIGH_TONGUE));

		/* Free experience gain */
		if (GET_EXP_CYCLE(ch) != exp_cycle) {
			/* reset daily exp */
			GET_EXP_TODAY(ch) = 0;
			gain_experience(ch, 1);
			GET_EXP_CYCLE(ch) = exp_cycle;
			}

		/* Update conditions */
		gain_condition(ch, FULL, 1);
		gain_condition(ch, DRUNK, -1);
		gain_condition(ch, THIRST, 1);

		/* Sleeping based on position */
		switch (GET_POS(ch)) {
			case POS_FIGHTING:	gain_condition(ch, TIRED, 2);	break;
			case POS_STANDING:	gain_condition(ch, TIRED, 1);	break;
			case POS_SITTING:	gain_condition(ch, TIRED, 1);	break;
			case POS_RESTING:	gain_condition(ch, TIRED, 0);	break;
			default:			gain_condition(ch, TIRED, -4);	break;
			}

		/* Sunburn! */
		switch (SECT(ch->in_room)) {
			case SECT_INSIDE:
				dam = 0;
				break;
			case SECT_FOREST_4:
				dam = 1;
				break;
			case SECT_FOREST_3:
				dam = 2;
				break;
			case SECT_MULTI:
			case SECT_BUILDING:
				if (!IS_COMPLETE(ch->in_room))
					dam = 2;
				else
					dam = 0;
				break;
			case SECT_MONUMENT_CLOSED:
				dam = 1;
				break;
			default:
				dam = 3;
			}

		if (DSC_FLAGGED(ch, DSC_DEATHS_WHISPER | DSC_EARTHMELD))
			dam = 0;

		if (IS_VAMPIRE(ch) && !IS_GOD(ch) && !IS_IMMORTAL(ch) && weather_info.sunlight != SUN_DARK && !ROOM_AFF_FLAGGED(ch->in_room, ROOM_AFF_DARK) && dam)
			if (damage(ch, ch, dam, ATTACK_SUNBURN, DAM_AGGRAVATED) < 0)
				continue;

		/* moving on.. */
		if (GET_POS(ch) < POS_STUNNED)
			continue;

		if (GET_QUIT_TIMER(ch) > 0)
			GET_QUIT_TIMER(ch) -= 1;

		/* regenerate */
		GET_MOVE(ch) = MIN(GET_MAX_MOVE(ch), GET_MOVE(ch) + move_gain(ch));

		if (GET_POS(ch) <= POS_STUNNED)
			update_pos(ch);

		/* Vampires must sleep between 10 and 2 */
		if (IS_VAMPIRE(ch) && GET_POS(ch) > POS_SLEEPING && GET_POS(ch) != POS_FIGHTING && weather_info.sunlight != SUN_DARK && time_info.hours >= 10 && time_info.hours <= 14 && GET_FORTITUDE(ch) < 8 && !PLR_FLAGGED(ch, PLR_NOSLEEP) && !PRF_FLAGGED(ch, PRF_RP)) {
			msg_to_char(ch, "The sun forces you into a deep sleep!\r\n");
			act("$n falls asleep!", TRUE, ch, 0, 0, TO_ROOM);
			if (GET_RIDING(ch)) {
				act("You fall off of $N!", FALSE, ch, 0, GET_RIDING(ch), TO_CHAR);
				act("$n falls off of $N!", FALSE, ch, 0, GET_RIDING(ch), TO_NOTVICT);
				}
			GET_POS(ch) = POS_SLEEPING;
			}
		if (IS_VAMPIRE(ch) && GET_POS(ch) == POS_SLEEPING && weather_info.sunlight == SUN_DARK && !IS_INJURED(ch, INJ_TORPOR | INJ_STAKED) && !DSC_FLAGGED(ch, DSC_EARTHMELD | DSC_BITUMENOUS_FLESH | DSC_MASQUE_OF_DEATH | DSC_DEATHS_WHISPER)) {
			msg_to_char(ch, "You no longer need rest.\r\n");
			do_wake(ch, "", 0, 0);
			}

		/* Humans sleeping */

		//remove that annoying ass sleep
		/*if (!IS_VAMPIRE(ch) && !IS_NPC(ch) && GET_COND(ch, TIRED) >= 420 && GET_POS(ch) > POS_SLEEPING && GET_POS(ch) != POS_FIGHTING && !PLR_FLAGGED(ch, PLR_NOSLEEP) && !PRF_FLAGGED(ch, PRF_RP)) {
			msg_to_char(ch, "You fall asleep!\r\n");
			act("$n falls asleep!", TRUE, ch, 0, 0, TO_ROOM);
			if (GET_RIDING(ch)) {
				act("You fall off of $N!", FALSE, ch, 0, GET_RIDING(ch), TO_CHAR);
				act("$n falls off of $N!", FALSE, ch, 0, GET_RIDING(ch), TO_NOTVICT);
				}
			GET_POS(ch) = POS_SLEEPING;
			}
		*/
		if (!IS_VAMPIRE(ch) && !IS_NPC(ch) && GET_COND(ch, TIRED) == 0 && GET_POS(ch) == POS_SLEEPING) {
			msg_to_char(ch, "You no longer need rest.\r\n");
			do_wake(ch, "", 0, 0);
			}

		if (!AWAKE(ch) && GET_MORPH(ch) == MORPH_PROTEAN_MIST && GET_PROTEAN(ch) < 6) {
			sprintf(buf, "%s has become $n!", PERS(ch, ch, 0));

			perform_morph(ch, MORPH_NONE);

			act(buf, TRUE, ch, 0, 0, TO_ROOM);
			msg_to_char(ch, "You revert to normal!\r\n");
			}

		/* Blood check */
		if (GET_BLOOD(ch) <= 0 && !GET_FED_ON_BY(ch) && !GET_FEEDING_FROM(ch)) {
			enter_torpor(ch, 0);
			continue;
			}

		/* Humanity check */
		if (!IS_NPC(ch) && GET_HUMANITY(ch) <= 0) {
			enter_torpor(ch, 1);
			continue;
			}

		random_encounter(ch);
		}


	/* Update objects every 5 seconds (used mainly for fire-starting) */
	for (j = object_list; j; j = j->next) {
		if (j->in_room != NOWHERE)
			if (OBJ_FLAGGED(j, ITEM_LIGHT))
				if (SECT(j->in_room) == SECT_BUILDING || SECT(j->in_room) == SECT_INSIDE) {
					room = world[j->in_room].home_room != NOWHERE ? real_room(world[j->in_room].home_room) : j->in_room;
					if (BUILDING_CAN_BURN(room))
						if (!world[room].burning) {
							world[room].burning = number(4, 12);
							if (world[room].people)
								act("A spark from $p ignites the room!", FALSE, world[room].people, j, 0, TO_CHAR | TO_ROOM);
							}
					}
		}
	}


/* Update PCs, NPCs, and objects */
void point_update(void) {
	extern int total_mobs(void);
	void update_mobile_special(Creature mob);
	void update_object_special(Object obj);

	Creature i, next_char, c;
	Object j, next_thing, jj, next_thing2;
	bool found = FALSE;
	room_rnum to_room;

	/* characters */
	for (i = character_list; i; i = next_char) {
		next_char = i->next;

		/* If this is a random-encounter mob and there's nobody else here, purge it */
		if (REAL_NPC(i) && MOB_FLAGGED(i, MOB_RANDOM_ENCOUNTER) && !FIGHTING(i)) {
			for (c = world[i->in_room].people, found = FALSE; c; c = c->next_in_room)
				if (c != i)
					found = TRUE;
			if (!found) {
				extract_char(i);
				continue;
				}
			}

		/* Only take blood if they have a link */
		if (i->desc && IS_VAMPIRE(i) && GET_SLIT_WRIST(i)) {
			GET_BLOOD(i) = MAX(3, GET_BLOOD(i) - 1);
			act("Some blood drips from an open wound in $n's wrist.", TRUE, i, 0, 0, TO_ROOM);
			msg_to_char(i, "Some blood drips from the open wound in your wrist.\r\n");
			}

		if (MOB_MILK_TIMER(i) > 0)
			MOB_MILK_TIMER(i)--;
		if (!IS_NPC(i) && GET_DEFECT_TIMER(i))
			GET_DEFECT_TIMER(i)--;

		if (GET_POS(i) >= POS_STUNNED && IS_NPC(i)) {
			/* Handled for PC's elsewhere: */
			if (!number(0, 4) && GET_DAMAGE(i) && GET_DAMAGE(i) > GET_AGG_DAMAGE(i))
				GET_DAMAGE(i) -= 1;
			GET_MOVE(i) += MIN(GET_MAX_MOVE(i), GET_MOVE(i) + move_gain(i) * 15);

			if (GET_POS(i) <= POS_STUNNED)
				update_pos(i);
			}

		/* Reproductive, capped at 50k */
		if (IS_NPC(i) && total_mobs() < 50000 && !MOB_FLAGGED(i, MOB_UNDEAD) && !number(0, BUILDING_TYPE(i->in_room) == BUILDING_STABLE ? 55000 : 95000))
			char_to_room(read_mobile(GET_MOB_RNUM(i), REAL), i->in_room);

		/* Special procedure: this must go last */
		if (IS_NPC(i))
			update_mobile_special(i);
		}

	/* objects */
	for (j = object_list; j; j = next_thing) {
		next_thing = j->next;	/* Next in object list */

		if (GET_OBJ_TYPE(j) == ITEM_CART && GET_OBJ_VAL(j, 2) > 1)
			GET_OBJ_VAL(j, 2) -= 1;

		if (OBJ_FLAGGED(j, ITEM_LIGHT)) {
			if (GET_OBJ_TIMER(j) == 2) {
				if (j->worn_by) {
					act("Your light begins to flicker and fade.", FALSE, j->worn_by, j, 0, TO_CHAR);
					act("$n's light begins to flicker and fade.", TRUE, j->worn_by, j, 0, TO_ROOM);
					}
				else if (j->carried_by)
					act("$p begins to flicker and fade.", FALSE, j->carried_by, j, 0, TO_CHAR);
				else if (j->in_room != NOWHERE)
					if (world[j->in_room].people)
						act("$p begins to flicker and fade.", FALSE, world[j->in_room].people, j, 0, TO_CHAR | TO_ROOM);
				}
			else if (GET_OBJ_TIMER(j) == 1) {
				if (j->worn_by) {
					act("Your light burns out.", FALSE, j->worn_by, j, 0, TO_CHAR);
					act("$n's light burns out.", TRUE, j->worn_by, j, 0, TO_ROOM);
					world[j->worn_by->in_room].light--;
					}
				else if (j->carried_by) {
					act("$p burns out.", FALSE, j->carried_by, j, 0, TO_CHAR);
					world[j->carried_by->in_room].light--;
					}
				else if (j->in_room != NOWHERE) {
					if (world[j->in_room].people)
						act("$p burns out.", FALSE, world[j->in_room].people, j, 0, TO_CHAR | TO_ROOM);
					world[j->in_room].light--;
					}
				}
			}

		if (GET_OBJ_TYPE(j) != ITEM_SHIP && j->in_room != NOWHERE && (SECT(j->in_room) == SECT_RIVER || SECT(j->in_room) == SECT_OCEAN)) {
			if (GET_OBJ_MATERIAL(j) == ITEM_MAT_IRON || GET_OBJ_MATERIAL(j) == ITEM_MAT_SILVER || GET_OBJ_MATERIAL(j) == ITEM_MAT_GOLD || GET_OBJ_MATERIAL(j) == ITEM_MAT_FLINT || GET_OBJ_MATERIAL(j) == ITEM_MAT_GLASS || GET_OBJ_MATERIAL(j) == ITEM_MAT_CLAY) {
				if (world[j->in_room].people)
					act("$p sinks quickly to the bottom.", TRUE, world[j->in_room].people, j, 0, TO_CHAR | TO_ROOM);
				extract_obj(j);
				continue;
				}
			else if (!number(0, 2) && SECT((to_room = real_shift(j->in_room, -1, 0))) != SECT_MOUNTAIN && SECT(to_room) != SECT_BUILDING && SECT(to_room) != SECT_MONUMENT_CLOSED && SECT(to_room) != SECT_MULTI) {
				if (world[j->in_room].people)
					act("$p floats west.", TRUE, world[j->in_room].people, j, 0, TO_CHAR | TO_ROOM);
				obj_to_room(j, to_room);
				if (world[j->in_room].people)
					act("$p floats in from the east.", TRUE, world[j->in_room].people, j, 0, TO_CHAR | TO_ROOM);
				}
			}

		/* timer count down */
		if (GET_OBJ_TIMER(j) > 0)
			GET_OBJ_TIMER(j)--;

		if (!GET_OBJ_TIMER(j) && !IS_OBJ_STAT(j, ITEM_SUPERIOR)) {
			switch (GET_OBJ_MATERIAL(j)) {
				case ITEM_MAT_FLESH:
					if (j->carried_by)
						act("$p decays in your hands.", FALSE, j->carried_by, j, 0, TO_CHAR);
					else if (j->worn_by)
						act("$p decays in your hands.", FALSE, j->worn_by, j, 0, TO_CHAR);
					else if ((j->in_room != NOWHERE) && (world[j->in_room].people)) {
						act("A quivering horde of maggots consumes $p.", TRUE, world[j->in_room].people, j, 0, TO_ROOM);
						act("A quivering horde of maggots consumes $p.", TRUE, world[j->in_room].people, j, 0, TO_CHAR);
						}
					break;
				case ITEM_MAT_IRON:
					if (j->carried_by)
						act("$p rusts in your hands.", FALSE, j->carried_by, j, 0, TO_CHAR);
					else if (j->worn_by)
						act("$p rusts in your hands.", FALSE, j->worn_by, j, 0, TO_CHAR);
					else if ((j->in_room != NOWHERE) && (world[j->in_room].people)) {
						act("$p rusts and disintegrates.", TRUE, world[j->in_room].people, j, 0, TO_ROOM);
						act("$p rusts and disintegrates.", TRUE, world[j->in_room].people, j, 0, TO_CHAR);
						}
					break;
				case ITEM_MAT_ROCK:
				case ITEM_MAT_FLINT:
					if (j->carried_by)
						act("$p disintegrates in your hands.", FALSE, j->carried_by, j, 0, TO_CHAR);
					else if (j->worn_by)
						act("$p disintegrates in your hands.", FALSE, j->worn_by, j, 0, TO_CHAR);
					else if ((j->in_room != NOWHERE) && (world[j->in_room].people)) {
						act("$p disintegrates.", TRUE, world[j->in_room].people, j, 0, TO_ROOM);
						act("$p disintegrates.", TRUE, world[j->in_room].people, j, 0, TO_CHAR);
						}
					break;
				case ITEM_MAT_GOLD:
				case ITEM_MAT_SILVER:
				case ITEM_MAT_CLAY:
					if (j->carried_by)
						act("$p cracks and disintegrates in your hands.", FALSE, j->carried_by, j, 0, TO_CHAR);
					else if (j->worn_by)
						act("$p cracks and disintegrates in your hands.", FALSE, j->worn_by, j, 0, TO_CHAR);
					else if ((j->in_room != NOWHERE) && (world[j->in_room].people)) {
						act("$p cracks and disintegrates.", TRUE, world[j->in_room].people, j, 0, TO_ROOM);
						act("$p cracks and disintegrates.", TRUE, world[j->in_room].people, j, 0, TO_CHAR);
						}
					break;
				case ITEM_MAT_WOOD:
				default:
					if (j->carried_by)
						act("$p rots in your hands.", FALSE, j->carried_by, j, 0, TO_CHAR);
					else if (j->worn_by)
						act("$p rots in your hands.", FALSE, j->worn_by, j, 0, TO_CHAR);
					else if ((j->in_room != NOWHERE) && (world[j->in_room].people)) {
						act("$p rots and disintegrates.", TRUE, world[j->in_room].people, j, 0, TO_ROOM);
						act("$p rots and disintegrates.", TRUE, world[j->in_room].people, j, 0, TO_CHAR);
						}
					break;
				}
			for (jj = j->contains; jj; jj = next_thing2) {
				next_thing2 = jj->next_content;		/* Next in inventory */

				if (j->in_obj)
					obj_to_obj(jj, j->in_obj);
				else if (j->carried_by)
					obj_to_char(jj, j->carried_by);
				else if (j->worn_by)
					obj_to_char(jj, j->worn_by);
				else if (j->in_room != NOWHERE)
					obj_to_room(jj, j->in_room);
				else
					extract_obj(jj);
				}
			extract_obj(j);
			continue;
			}

		/* If the object survived.. this MUST be last */
		update_object_special(j);
		}
	}


/* Primarily used for burning buildings */
void room_update(void) {
	void disassociate_building(room_rnum room);
	void die(Creature ch);
	void death_log(Creature ch, Creature killer, int type);
	void delete_room(room_rnum rnum);
	void disperse_resources(room_rnum room);
	void fill_trench(room_rnum room);

	Creature ch;
	Object o, next_o;
	room_rnum room, i;

	for (room = 0; room < MAP_SIZE; room++) {
		if (SECT(room) == SECT_TRENCH && GET_BUILD_VALUE(room) >= 0) {
			if (weather_info.sky >= SKY_RAINING) {
				GET_BUILD_VALUE(room) += 5;
				if (GET_BUILD_VALUE(room) >= 500)
					fill_trench(room);
				}

			/* Check for adjacent water to flow in */
			for (i = 0; i < NUM_2D_DIRS; i++)
				if (SECT(real_shift(room, shift_dir[i][0], shift_dir[i][1])) == SECT_OCEAN || SECT(real_shift(room, shift_dir[i][0], shift_dir[i][1])) == SECT_RIVER)
					if (!number(0, 12)) {
						if (world[room].people)
							act("Water flows into the trench, filling it quickly!", FALSE, world[room].people, 0, 0, TO_CHAR | TO_ROOM);
						fill_trench(room);
						}
			}

		if (room_affected_by_spell(room, ATYPE_NOCTURNE) && weather_info.sunlight != SUN_DARK) {
			affect_from_room(room, ATYPE_NOCTURNE);
			if (world[room].people)
				act("The darkness dissipates.", FALSE, world[room].people, 0, 0, TO_CHAR | TO_ROOM);
			}

		if (world[room].burning) {
			/* Reduce by one tick */
			world[room].burning--;

			/* Time's up! */
			if (world[room].burning == 0) {
				if (real_empire(world[room].owner) != -1)
					empire[real_empire(world[room].owner)].territory--;
				world[room].owner = 0;

				disperse_resources(room);
				disassociate_building(room);

				if (world[room].people)
					act("The buildings collapses in flames around you!", FALSE, world[room].people, 0, 0, TO_CHAR | TO_ROOM);
				while ((ch = world[room].people)) {
					if (!IS_NPC(ch))
						death_log(ch, ch, TYPE_SUFFERING);
					die(ch);
					}

				/* Destroy 50% of the objects */
				for (o = world[room].contents; o; o = next_o) {
					next_o = o->next_content;
					if (!number(0, 1))
						extract_obj(o);
					}

				continue;
				}

			/* Otherwise, just send a message */
			if (world[room].people)
				act("The walls crackle and crisp as they burn!", FALSE, world[room].people, 0, 0, TO_CHAR | TO_ROOM);
			}
		}

	/* For remaining interior rooms, make sure everyone knows the place is crispy */
	for (i = MAP_SIZE; i <= top_of_world; i++)
		if (world[i].home_room != NOWHERE && world[real_room(world[i].home_room)].burning && world[i].people)
			act("The walls crackle and crisp as they burn!", FALSE, world[i].people, 0, 0, TO_CHAR | TO_ROOM);
	}


void run_idling(void) {
	Creature i, next_i;

	for (i = character_list; i; i = next_i) {
		next_i = i->next;
		if (!IS_NPC(i))
			check_idling(i);
		}
	}