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