/* ************************************************************************
* 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);
}
}