/* * $Id: update.c,v 1.121 1999/05/06 10:55:30 kostik Exp $ */ /*************************************************************************** * ANATOLIA 2.1 is copyright 1996-1997 Serdar BULUT * * ANATOLIA has been brought to you by ANATOLIA consortium * * Serdar BULUT {Chronos} bulut@rorqual.cc.metu.edu.tr * * Ibrahim Canpunar {Mandrake} 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 <string.h> #include <time.h> #include "merc.h" #include "update.h" #include "mob_prog.h" #include "obj_prog.h" #include "fight.h" /* command procedures needed */ DECLARE_DO_FUN(do_human ); DECLARE_DO_FUN(do_murder ); DECLARE_DO_FUN(do_rescue ); DECLARE_DO_FUN(do_stand ); DECLARE_DO_FUN(do_track ); DECLARE_DO_FUN(do_yell ); DECLARE_DO_FUN(do_asave ); void back_home (CHAR_DATA *ch); /* * Local functions. */ int hit_gain (CHAR_DATA *ch); int mana_gain (CHAR_DATA *ch); int move_gain (CHAR_DATA *ch); void mobile_update (void); void weather_update (void); void char_update (void); void obj_update (void); void aggr_update (void); void clan_item_update(void); int potion_cure_level (OBJ_DATA *potion); int potion_arm_level (OBJ_DATA *potion); bool potion_cure_blind (OBJ_DATA *potion); bool potion_cure_poison (OBJ_DATA *potion); bool potion_cure_disease (OBJ_DATA *potion); /* below done by chronos */ void quest_update args((void)); void auction_update args((void)); void light_update args((void)); void room_update args((void)); void room_affect_update args((void)); void check_reboot args((void)); void track_update args((void)); /* used for saving */ int save_number = 0; int rebooter = 0; /* * Advancement stuff. */ void advance_level(CHAR_DATA *ch) { int add_hp; int add_mana; int add_move; int add_prac; class_t *cl; if (IS_NPC(ch)) { bug("Advance_level: a mob to advance!", 0); return; } if ((cl = class_lookup(ch->class)) == NULL) { log_printf("advance_level", "%s: unknown class %d", ch->name, ch->class); return; } ch->pcdata->last_level = (ch->played + (int) (current_time - ch->logon)) / 3600; set_title(ch, title_lookup(ch)); if (ch->pcdata->plevels > 0) { ch->pcdata->plevels--; return; } add_hp = (con_app[get_curr_stat(ch,STAT_CON)].hitp + number_range(1,5)) - 3; add_hp = (add_hp * cl->hp_rate) / 100; add_mana = number_range(get_curr_stat(ch,STAT_INT)/2, (2*get_curr_stat(ch,STAT_INT) + get_curr_stat(ch,STAT_WIS)/5)); add_mana = (add_mana * cl->mana_rate) / 100; add_move = number_range(1, (get_curr_stat(ch,STAT_CON) + get_curr_stat(ch,STAT_DEX)) / 6); add_prac = wis_app[get_curr_stat(ch,STAT_WIS)].practice; add_hp = UMAX(3, add_hp); add_mana = UMAX(3, add_mana); add_move = UMAX(6, add_move); if (ch->sex == SEX_FEMALE) { add_hp -= 1; add_mana += 2; } ch->max_hit += add_hp; ch->max_mana += add_mana; ch->max_move += add_move; ch->practice += add_prac; ch->train += ch->level % 5 ? 0 : 1; ch->pcdata->perm_hit += add_hp; ch->pcdata->perm_mana += add_mana; ch->pcdata->perm_move += add_move; char_printf(ch, "Your gain is {C%d{x hp, {C%d{x mana, {C%d{x mv {C%d{x prac.\n", add_hp, add_mana, add_move, add_prac); } void gain_exp(CHAR_DATA *ch, int gain) { if (IS_NPC(ch) || ch->level >= LEVEL_HERO) return; if (IS_SET(ch->plr_flags, PLR_NOEXP) && gain > 0) { char_puts("You can't gain exp without your spirit.\n", ch); return; } ch->exp += gain; ch->exp_tl += gain; while (ch->level < LEVEL_HERO && exp_to_level(ch) <= 0) { class_t *cl; char_puts("{CYou raise a level!!{x ", ch); ch->level++; ch->exp_tl = 0; if ((cl = class_lookup(ch->class)) != NULL && cl->death_limit != 0 && ch->level == MIN_PK_LEVEL) ch->wimpy = 0; if (ch->level == 91) log_printf("%s made level 91.", ch->name); wiznet("$N has attained level $j!", ch, (const void*) ch->level, WIZ_LEVELS, 0, 0); advance_level(ch); save_char_obj(ch, FALSE); } } /* * Regeneration stuff. */ int hit_gain(CHAR_DATA *ch) { int gain; int number; class_t *cl; if (ch->in_room == NULL || (cl = class_lookup(ch->class)) == NULL) return 0; if (IS_NPC(ch)) { gain = 5 + ch->level; if (IS_AFFECTED(ch, AFF_REGENERATION)) gain *= 2; switch(ch->position) { default: gain /= 2; break; case POS_SLEEPING: gain = 3 * gain/2; break; case POS_RESTING: break; case POS_FIGHTING: gain /= 3; break; } } else { gain = UMAX(3, 2 * get_curr_stat(ch,STAT_CON) + (7 * ch->level) / 4); gain = (gain * cl->hp_rate) / 100; number = number_percent(); if (number < get_skill(ch, gsn_fast_healing)) { gain += number * gain / 100; if (ch->hit < ch->max_hit) check_improve(ch, gsn_fast_healing, TRUE, 8); } if (number < get_skill(ch, gsn_trance)) { gain += number * gain / 150; if (ch->mana < ch->max_mana) check_improve(ch, gsn_trance, TRUE, 8); } switch (ch->position) { default: gain /= 4; break; case POS_SLEEPING: break; case POS_RESTING: gain /= 2; break; case POS_FIGHTING: gain /= 6; break; } if (ch->pcdata->condition[COND_HUNGER] < 0) gain = 0; if (ch->pcdata->condition[COND_THIRST] < 0) gain = 0; } gain = gain * ch->in_room->heal_rate / 100; if (ch->on != NULL && ch->on->pIndexData->item_type == ITEM_FURNITURE) gain = gain * ch->on->value[3] / 100; if (IS_AFFECTED(ch, AFF_POISON)) gain /= 4; if (IS_AFFECTED(ch, AFF_PLAGUE)) gain /= 8; if (IS_AFFECTED(ch, AFF_HASTE)) gain /= 2; if (IS_AFFECTED(ch, AFF_SLOW)) gain /= 2; if (get_curr_stat(ch, STAT_CON) > 20) gain = (gain * 14) / 10; if (IS_HARA_KIRI(ch)) gain *= 3; return UMIN(gain, ch->max_hit - ch->hit); } int mana_gain(CHAR_DATA *ch) { int gain; int number; class_t *cl; if (ch->in_room == NULL || (cl = class_lookup(ch->class)) == NULL) return 0; if (IS_NPC(ch)) { gain = 5 + ch->level; switch (ch->position) { default: gain /= 2; break; case POS_SLEEPING: gain = 3 * gain/2; break; case POS_RESTING: break; case POS_FIGHTING: gain /= 3; break; } } else { gain = get_curr_stat(ch,STAT_WIS) + (2 * get_curr_stat(ch,STAT_INT)) + ch->level; gain = (gain * cl->mana_rate) / 100; number = number_percent(); if (number < get_skill(ch,gsn_meditation)) { gain += number * gain / 100; if (ch->mana < ch->max_mana) check_improve(ch,gsn_meditation,TRUE,8); } if (number < get_skill(ch,gsn_trance)) { gain += number * gain / 100; if (ch->mana < ch->max_mana) check_improve(ch,gsn_trance,TRUE,8); } if (!IS_SET(cl->flags, CLASS_MAGIC)) gain /= 2; switch (ch->position) { default: gain /= 4; break; case POS_SLEEPING: break; case POS_RESTING: gain /= 2; break; case POS_FIGHTING: gain /= 6; break; } if (ch->pcdata->condition[COND_HUNGER] < 0) gain = 0; if (ch->pcdata->condition[COND_THIRST] < 0) gain = 0; } gain = gain * ch->in_room->mana_rate / 100; if (ch->on != NULL && ch->on->pIndexData->item_type == ITEM_FURNITURE) gain = gain * ch->on->value[4] / 100; if (IS_AFFECTED(ch, AFF_POISON)) gain /= 4; if (IS_AFFECTED(ch, AFF_PLAGUE)) gain /= 8; if (IS_AFFECTED(ch,AFF_HASTE)) gain /= 2 ; if (IS_AFFECTED(ch,AFF_SLOW)) gain /= 2 ; if (get_curr_stat(ch,STAT_INT) > 20) gain = (gain * 13) / 10; if (get_curr_stat(ch,STAT_WIS) > 20) gain = (gain * 11) / 10; if (IS_HARA_KIRI(ch)) gain *= 3; return UMIN(gain, ch->max_mana - ch->mana); } int move_gain(CHAR_DATA *ch) { int gain; if (ch->in_room == NULL) return 0; if (IS_NPC(ch)) { gain = ch->level; } else { gain = UMAX(15, 2 * ch->level); switch (ch->position) { case POS_SLEEPING: gain += 2 * (get_curr_stat(ch,STAT_DEX)); break; case POS_RESTING: gain += get_curr_stat(ch,STAT_DEX); break; } if (ch->pcdata->condition[COND_HUNGER] < 0) gain = 3; if (ch->pcdata->condition[COND_THIRST] < 0) gain = 3; } gain = gain * ch->in_room->heal_rate/100; if (ch->on != NULL && ch->on->pIndexData->item_type == ITEM_FURNITURE) gain = gain * ch->on->value[3] / 100; if (IS_AFFECTED(ch, AFF_POISON)) gain /= 4; if (IS_AFFECTED(ch, AFF_PLAGUE)) gain /= 8; if (IS_AFFECTED(ch,AFF_HASTE) || IS_AFFECTED(ch,AFF_SLOW)) gain /=2 ; if (get_curr_stat(ch,STAT_DEX) > 20) gain *= (14 /10); if (IS_HARA_KIRI(ch)) gain *= 3; return UMIN(gain, ch->max_move - ch->move); } void gain_condition(CHAR_DATA *ch, int iCond, int value) { int condition; int damage_hunger; int fdone; CHAR_DATA *vch,*vch_next; if (value == 0 || IS_NPC(ch) || ch->level >= LEVEL_IMMORTAL) return; if (HAS_SKILL(ch, gsn_vampire) && (iCond == COND_THIRST || iCond == COND_FULL || iCond == COND_HUNGER)) return; condition = ch->pcdata->condition[iCond]; ch->pcdata->condition[iCond] = URANGE(-6, condition + value, 96); if (iCond == COND_FULL && (ch->pcdata->condition[COND_FULL] < 0)) ch->pcdata->condition[COND_FULL] = 0; if ((iCond == COND_DRUNK) && (ch->pcdata->condition[COND_DRUNK] < 1)) ch->pcdata->condition[COND_DRUNK] = 0; if (ch->pcdata->condition[iCond] < 1 && ch->pcdata->condition[iCond] > -6) { switch (iCond) { case COND_HUNGER: char_puts("You are hungry.\n", ch); break; case COND_THIRST: char_puts("You are thirsty.\n", ch); break; case COND_DRUNK: if (condition != 0) char_puts("You are sober.\n", ch); break; case COND_BLOODLUST: if (condition != 0) char_puts("You are hungry for blood.\n", ch); break; case COND_DESIRE: if (condition != 0) char_puts("You have missed your home.\n", ch); break; } } if (ch->pcdata->condition[iCond] == -6 && ch->level >= MIN_PK_LEVEL) { switch (iCond) { case COND_HUNGER: char_puts("You are starving!\n", ch); act("$n is starving!", ch, NULL, NULL, TO_ROOM); damage_hunger = ch->max_hit * number_range(2, 4) / 100; if (!damage_hunger) damage_hunger = 1; damage(ch, ch, damage_hunger, TYPE_HUNGER, DAM_HUNGER, TRUE); if (ch->position == POS_SLEEPING) return; break; case COND_THIRST: char_puts("You are dying of thrist!\n", ch); act("$n is dying of thirst!", ch, NULL, NULL, TO_ROOM); damage_hunger = ch->max_hit * number_range(2, 4) / 100; if (!damage_hunger) damage_hunger = 1; damage(ch, ch, damage_hunger, TYPE_HUNGER, DAM_THIRST, TRUE); if (ch->position == POS_SLEEPING) return; break; case COND_BLOODLUST: fdone = 0; char_puts("You are suffering from thrist of blood!\n", ch); act("$n is suffering from thirst of blood!", ch, NULL, NULL, TO_ROOM); if (ch->in_room && ch->in_room->people && ch->fighting == NULL) { if (!IS_AWAKE(ch)) do_stand(ch, str_empty); for (vch = ch->in_room->people; vch != NULL && ch->fighting == NULL; vch = vch_next) { vch_next = vch->next_in_room; if (IS_IMMORTAL(vch)) continue; if (ch != vch && can_see(ch, vch) && !is_safe_nomessage(ch, vch)) { do_yell(ch, "BLOOD! I NEED BLOOD!"); do_murder(ch, vch->name); fdone = 1; } } } if (fdone) break; damage_hunger = ch->max_hit * number_range(2, 4) / 100; if (!damage_hunger) damage_hunger = 1; damage(ch, ch, damage_hunger, TYPE_HUNGER, DAM_THIRST, TRUE); if (ch->position == POS_SLEEPING) return; break; case COND_DESIRE: char_puts("You want to go your home!\n", ch); act("$n desires for $s home!", ch, NULL, NULL, TO_ROOM); if (ch->position >= POS_STANDING) move_char(ch, number_door(), FALSE); break; } } } /* * Mob autonomous action. * This function takes 25% to 35% of ALL Merc cpu time. * -- Furey */ void mobile_update(void) { CHAR_DATA *ch, *ch_next; EXIT_DATA *pexit; int door; OBJ_DATA *obj; /* Examine all mobs. */ for (ch = char_list; ch; ch = ch_next) { bool bust_prompt = FALSE; flag64_t act; ch_next = ch->next; if (!ch->in_room) continue; if (ch->position == POS_FIGHTING) SET_FIGHT_TIME(ch); /* permanent spellbane */ if (!IS_NPC(ch)) { #if 0 if (ch->level < LEVEL_IMMORTAL && get_skill(ch, gsn_spellbane) && !is_affected(ch, gsn_spellbane)) do_spellbane(ch, str_empty); #endif /* update ghost state */ if (ch->last_death_time != -1 && current_time - ch->last_death_time >= GHOST_DELAY_TIME && IS_SET(ch->plr_flags, PLR_GHOST)) { char_puts("You return to your normal form.\n", ch); REMOVE_BIT(ch->plr_flags, PLR_GHOST); } } /* update pumped state */ if (ch->last_fight_time != -1 && current_time - ch->last_fight_time >= FIGHT_DELAY_TIME && IS_PUMPED(ch)) { REMOVE_BIT((ch)->plr_flags, PLR_PUMPED); if (!IS_NPC(ch) && ch->desc != NULL && ch->desc->pString == NULL && (ch->last_death_time == -1 || ch->last_death_time < ch->last_fight_time)) { act("You settle down.", ch, NULL, NULL, TO_CHAR); } } if (IS_AFFECTED(ch, AFF_REGENERATION) && ch->in_room != NULL) { ch->hit = UMIN(ch->hit + ch->level / 10, ch->max_hit); if (ch->race == 18 /* troll */) ch->hit = UMIN(ch->hit + ch->level / 10, ch->max_hit); if (ch->hit != ch->max_hit) bust_prompt = TRUE; } if (IS_AFFECTED(ch, AFF_CORRUPTION) && ch->in_room != NULL) { ch->hit -= ch->level / 10; if (ch->hit < 1) { if (IS_IMMORTAL(ch)) ch->hit = 1; else { ch->position = POS_DEAD; handle_death(ch, ch); continue; } } bust_prompt = TRUE; } if (ch->desc && bust_prompt && !ch->desc->pString && !ch->desc->showstr_point && !IS_SET(ch->comm, COMM_NOBUST)) char_puts(str_empty, ch); /* * that's all for PCs and charmed mobiles */ if (!IS_NPC(ch) || IS_AFFECTED(ch, AFF_CHARM)) continue; act = ch->pIndexData->act; if (IS_SET(act, ACT_HUNTER) && ch->hunting) hunt_victim(ch); if (ch->in_room->area->empty && !IS_SET(act, ACT_UPDATE_ALWAYS)) continue; /* Examine call for special procedure */ if (ch->spec_fun != 0) { if ((*ch->spec_fun) (ch)) continue; } if (ch->pIndexData->pShop != NULL /* give him some gold */ || (ch->gold * 100 + ch->silver) < ch->pIndexData->wealth) { ch->gold += ch->pIndexData->wealth * number_range(1,20)/5000000; ch->silver += ch->pIndexData->wealth * number_range(1,20)/50000; } /* check triggers (only if mobile still in default position) */ if (ch->position == ch->pIndexData->default_pos) { if (HAS_TRIGGER(ch, TRIG_DELAY) && ch->mprog_delay > 0) { if (--ch->mprog_delay <= 0) { mp_percent_trigger(ch, NULL, NULL, NULL, TRIG_DELAY); continue; } } if (HAS_TRIGGER(ch, TRIG_RANDOM)) { if(mp_percent_trigger(ch, NULL, NULL, NULL, TRIG_RANDOM)) continue; } } /* potion using and stuff for intelligent mobs */ if (ch->pIndexData->pShop == NULL && (ch->position == POS_STANDING || ch->position == POS_RESTING || ch->position == POS_FIGHTING) && get_curr_stat(ch, STAT_INT) > 15 && (ch->hit < ch->max_hit * 90 / 100 || IS_AFFECTED(ch, AFF_BLIND) || IS_AFFECTED(ch, AFF_POISON) || IS_AFFECTED(ch, AFF_PLAGUE) || ch->fighting != NULL)) { for (obj = ch->carrying; obj; obj = obj->next_content) { if (obj->pIndexData->item_type != ITEM_POTION) continue; if (ch->hit < ch->max_hit * 90 / 100) { int cl = potion_cure_level(obj); if (cl > 0) { if (ch->hit < ch->max_hit*0.5 && cl > 3) { quaff_obj(ch, obj); continue; } if (ch->hit < ch->max_hit*0.7) { quaff_obj(ch, obj); continue; } } } if (IS_AFFECTED(ch, AFF_POISON) && potion_cure_poison(obj)) { quaff_obj(ch, obj); continue; } if (IS_AFFECTED(ch, AFF_PLAGUE) && potion_cure_disease(obj)) { quaff_obj(ch, obj); continue; } if (IS_AFFECTED(ch, AFF_BLIND) && potion_cure_blind(obj)) { quaff_obj(ch, obj); continue; } if (ch->fighting) { int al = potion_arm_level(obj); if (ch->level - ch->fighting->level < 7 && al > 3) { quaff_obj(ch, obj); continue; } if (ch->level - ch->fighting->level < 8 && al > 2) { quaff_obj(ch, obj); continue; } if (ch->level - ch->fighting->level < 9 && al > 1) { quaff_obj(ch, obj); continue; } if (ch->level - ch->fighting->level < 10 && al > 0) { quaff_obj(ch, obj); continue; } } } } /* That's all for sleeping / busy monster, and empty zones */ if (ch->position != POS_STANDING) continue; /* Scavenge */ if (IS_SET(act, ACT_SCAVENGER) && ch->in_room->contents != NULL && number_bits(6) == 0) { OBJ_DATA *obj; OBJ_DATA *obj_best = NULL; int max = 1; for (obj = ch->in_room->contents; obj; obj = obj->next_content) { if (CAN_WEAR(obj, ITEM_TAKE) && can_loot(ch, obj) && obj->cost > max) { obj_best = obj; max = obj->cost; } } if (obj_best) get_obj(ch, obj_best, NULL); } /* Wander */ if (!IS_SET(act, ACT_SENTINEL) && number_bits(3) == 0 && (door = number_bits(5)) <= 5 && !RIDDEN(ch) && (pexit = ch->in_room->exit[door]) != NULL && pexit->to_room.r != NULL && !IS_SET(pexit->exit_info, EX_CLOSED) && !IS_SET(pexit->to_room.r->room_flags, ROOM_NOMOB) && (!IS_SET(act, ACT_STAY_AREA) || pexit->to_room.r->area == ch->in_room->area) && (!IS_SET(act, ACT_AGGRESSIVE) || !IS_SET(pexit->to_room.r->room_flags, ROOM_PEACE | ROOM_SAFE)) && (!IS_SET(act, ACT_OUTDOORS) || !IS_SET(pexit->to_room.r->room_flags, ROOM_INDOORS)) && (!IS_SET(act, ACT_INDOORS) || IS_SET(pexit->to_room.r->room_flags, ROOM_INDOORS))) move_char(ch, door, FALSE); } } int potion_cure_level(OBJ_DATA *potion) { int cl; int i; cl = 0; for (i=1;i<5;i++) { if (sn_lookup("cure critical") == potion->value[i]) cl += 3; if (sn_lookup("cure light") == potion->value[i]) cl += 1; if (sn_lookup("cure serious") == potion->value[i]) cl += 2; if (sn_lookup("heal") == potion->value[i]) cl += 4; } return(cl); } int potion_arm_level(OBJ_DATA *potion) { int al; int i; al = 0; for (i=1;i<5;i++) { if (sn_lookup("armor") == potion->value[i]) al += 1; if (sn_lookup("shield") == potion->value[i]) al += 1; if (sn_lookup("stone skin") == potion->value[i]) al += 2; if (sn_lookup("sanctuary") == potion->value[i]) al += 4; if (sn_lookup("protection") == potion->value[i]) al += 3; } return(al); } bool potion_cure_blind(OBJ_DATA *potion) { int i; for (i=0;i<5;i++) { if (sn_lookup("cure blindness") == potion->value[i]) return(TRUE); } return(FALSE); } bool potion_cure_poison(OBJ_DATA *potion) { int i; for (i=0;i<5;i++) { if (sn_lookup("cure poison") == potion->value[i]) return(TRUE); } return(FALSE); } bool potion_cure_disease(OBJ_DATA *potion) { int i; for (i=0;i<5;i++) { if (sn_lookup("cure disease") == potion->value[i]) return(TRUE); } return(FALSE); } /* * Update the weather. */ void weather_update(void) { CHAR_DATA *ch; int diff; const char *msg_daytime = NULL; const char *msg_weather = NULL; switch (++time_info.hour) { case 5: weather_info.sunlight = SUN_LIGHT; msg_daytime = "The day has begun."; break; case 6: weather_info.sunlight = SUN_RISE; msg_daytime = "The sun rises in the east."; break; case 19: weather_info.sunlight = SUN_SET; msg_daytime = "The sun slowly disappears in the west."; break; case 20: weather_info.sunlight = SUN_DARK; msg_daytime = "The night has begun."; break; case 24: time_info.hour = 0; time_info.day++; break; } if (time_info.day >= 35) { time_info.day = 0; time_info.month++; } if (time_info.month >= 17) { time_info.month = 0; time_info.year++; } /* * Weather change. */ if (time_info.month >= 9 && time_info.month <= 16) diff = weather_info.mmhg > 985 ? -2 : 2; else diff = weather_info.mmhg > 1015 ? -2 : 2; weather_info.change += diff * dice(1, 4) + dice(2, 6) - dice(2, 6); weather_info.change = UMAX(weather_info.change, -12); weather_info.change = UMIN(weather_info.change, 12); weather_info.mmhg += weather_info.change; weather_info.mmhg = UMAX(weather_info.mmhg, 960); weather_info.mmhg = UMIN(weather_info.mmhg, 1040); switch (weather_info.sky) { default: bug("Weather_update: bad sky %d.", weather_info.sky); weather_info.sky = SKY_CLOUDLESS; break; case SKY_CLOUDLESS: if (weather_info.mmhg < 990 || (weather_info.mmhg < 1010 && number_bits(2) == 0)) { msg_weather = "The sky is getting cloudy."; weather_info.sky = SKY_CLOUDY; } break; case SKY_CLOUDY: if (weather_info.mmhg < 970 || (weather_info.mmhg < 990 && number_bits(2) == 0)) { msg_weather = "It starts to rain."; weather_info.sky = SKY_RAINING; } else if (weather_info.mmhg > 1030 && number_bits(2) == 0) { msg_weather = "The clouds disappear."; weather_info.sky = SKY_CLOUDLESS; } break; case SKY_RAINING: if (weather_info.mmhg > 1030 || (weather_info.mmhg > 1010 && number_bits(2) == 0)) { msg_weather = "The rain stopped."; weather_info.sky = SKY_CLOUDY; } else if (weather_info.mmhg < 970 && number_bits(2) == 0) { msg_weather = "Lightning flashes in the sky."; weather_info.sky = SKY_LIGHTNING; } break; case SKY_LIGHTNING: if (weather_info.mmhg > 1010 || (weather_info.mmhg > 990 && number_bits(2) == 0)) { msg_weather = "The lightning has stopped."; weather_info.sky = SKY_RAINING; } break; } if (!msg_daytime && !msg_weather) return; for (ch = char_list; ch; ch = ch->next) { if (IS_NPC(ch) && !HAS_TRIGGER(ch, TRIG_ACT)) continue; if (!IS_OUTSIDE(ch) || !IS_AWAKE(ch)) continue; act(msg_daytime, ch, NULL, NULL, TO_CHAR); act(msg_weather, ch, NULL, NULL, TO_CHAR); } } /* * Update all chars, including mobs. */ void char_update(void) { CHAR_DATA *ch; CHAR_DATA *ch_next; static time_t last_save_time = -1; /* update save counter */ save_number++; if (save_number > 29) save_number = 0; for (ch = char_list; ch; ch = ch_next) { AFFECT_DATA *paf; AFFECT_DATA *paf_next; int chance; race_t *r = race_lookup(ch->race); ch_next = ch->next; if (!r) continue; /* reset path find */ if (!IS_NPC(ch) && (chance = get_skill(ch, gsn_path_find))) { if (number_percent() < chance) { ch->endur += chance / 2; check_improve(ch, gsn_path_find, TRUE, 8); } else check_improve(ch, gsn_path_find, FALSE, 16); } if (!ch->fighting) { flag64_t skip = AFF_FLYING; affect_check(ch, TO_AFFECTS, -1); /* Remove caltrops effect after fight off */ if (is_affected(ch, gsn_caltrops)) affect_strip(ch, gsn_caltrops); if (!MOUNTED(ch)) { if (!IS_AFFECTED(ch, AFF_HIDE) && (r->aff & AFF_HIDE)) char_puts("You step back into the shadows.\n", ch); if (!IS_AFFECTED(ch, AFF_SNEAK) && (r->aff & AFF_SNEAK)) char_puts("You move silently again.\n", ch); } else skip |= AFF_HIDE | AFF_FADE | AFF_INVIS | AFF_IMP_INVIS | AFF_SNEAK | AFF_CAMOUFLAGE; SET_BIT(ch->affected_by, r->aff & ~skip); } /* Remove vampire effect when morning. */ if (is_affected(ch, gsn_vampire) && (weather_info.sunlight == SUN_LIGHT || weather_info.sunlight == SUN_RISE)) do_human(ch, str_empty); if (!IS_NPC(ch) && is_affected(ch, gsn_thumbling)) { if (dice(5, 6) > get_curr_stat(ch, STAT_DEX)) { act("You failed to reach the true source of tennis ball power.", ch, NULL, NULL, TO_CHAR); act("$n falls to the ground flat on $s face.", ch, NULL, NULL, TO_ROOM); affect_strip(ch, gsn_thumbling); } } if (ch->position >= POS_STUNNED) { int old_hit = ch->hit; int old_mana = ch->mana; int old_move = ch->move; /* check to see if we need to go home */ if (IS_NPC(ch) && ch->zone != NULL && ch->in_room != NULL && ch->zone != ch->in_room->area && ch->desc == NULL && ch->fighting == NULL /* && ch->progtypes==0 */ && !IS_AFFECTED(ch,AFF_CHARM) && ch->last_fought == NULL && !RIDDEN(ch)) { if (ch->in_mind != NULL && ch->pIndexData->vnum > 100) back_home(ch); else { act("$n wanders on home.", ch, NULL, NULL, TO_ROOM); extract_char(ch, 0); } continue; } if (ch->hit < ch->max_hit) ch->hit += hit_gain(ch); else ch->hit = ch->max_hit; if (ch->mana < ch->max_mana) ch->mana += mana_gain(ch); else ch->mana = ch->max_mana; if (ch->move < ch->max_move) ch->move += move_gain(ch); else ch->move = ch->max_move; if (ch->desc && (old_hit != ch->hit || old_mana != ch->mana || old_move != ch->move) && !ch->desc->pString && !ch->desc->showstr_point && !IS_SET(ch->comm, COMM_NOBUST)) char_puts(str_empty, ch); } if (ch->position == POS_STUNNED) update_pos(ch); if (!IS_NPC(ch) && ch->level < LEVEL_IMMORTAL && ch->in_room != NULL) { OBJ_DATA *obj; if ((obj = get_eq_char(ch, WEAR_LIGHT)) && obj->pIndexData->item_type == ITEM_LIGHT && obj->value[2] > 0) { if (--obj->value[2] == 0) { if (ch->in_room->light > 0) --ch->in_room->light; act("$p goes out.", ch, obj, NULL, TO_ROOM); act("$p flickers and goes out.", ch, obj, NULL, TO_CHAR); extract_obj(obj, 0); } else if (obj->value[2] <= 5) act("$p flickers.", ch, obj, NULL, TO_CHAR); } if (++ch->timer >= 12) { if (ch->was_in_room == NULL) { ch->was_in_room = ch->in_room; if (ch->fighting != NULL) stop_fighting(ch, TRUE); act("$n disappears into the void.", ch, NULL, NULL, TO_ROOM); char_puts("You disappear " "into the void.\n", ch); if (ch->level > 1) save_char_obj(ch, FALSE); char_from_room(ch); char_to_room(ch, get_room_index(ROOM_VNUM_LIMBO)); if (JUST_KILLED(ch)) continue; } } if (!ch->was_in_room) { gain_condition(ch, COND_DRUNK, -1); if (HAS_SKILL(ch, gsn_vampire)) gain_condition(ch, COND_BLOODLUST, -1); gain_condition(ch, COND_FULL, ch->size > SIZE_MEDIUM ? -4 : -2); if (ch->in_room->sector_type == SECT_DESERT) gain_condition(ch, COND_THIRST, -3); else gain_condition(ch, COND_THIRST, -1); gain_condition(ch, COND_HUNGER, ch->size > SIZE_MEDIUM ? -2 : -1); } } for (paf = ch->affected; paf != NULL; paf = paf_next) { paf_next = paf->next; if (paf->duration > 0) { paf->duration--; if (number_range(0, 4) == 0 && paf->level > 0) paf->level--; /* spell strength fades with time */ } else if (paf->duration == 0) { skill_t *sk; if ((paf_next == NULL || paf_next->type != paf->type || paf_next->duration > 0) && paf->type > 0 && (sk = skill_lookup(paf->type)) && !IS_NULLSTR(sk->msg_off)) act_puts(sk->msg_off, ch, NULL, NULL, TO_CHAR, POS_DEAD); affect_remove(ch, paf); } } /* * Careful with the damages here, * MUST NOT refer to ch after damage taken, * as it may be lethal damage (on NPC). */ if (is_affected(ch, gsn_witch_curse)) { AFFECT_DATA *af, witch; if (ch->in_room == NULL) continue; act("The witch curse makes $n feel $s life slipping away.", ch, NULL, NULL, TO_ROOM); char_puts("The witch curse makes you feeling your life slipping away.\n", ch); for (af = ch->affected; af!= NULL; af = af->next) if (af->type == gsn_witch_curse) break; if (af == NULL) continue; if (af->level == 1) continue; witch.where = af->where; witch.type = af->type; witch.level = af->level; witch.duration = af->duration; witch.location = af->location; witch.modifier = af->modifier * 2; witch.bitvector = 0; affect_remove(ch, af); affect_to_char(ch ,&witch); ch->hit = UMIN(ch->hit, ch->max_hit); if (ch->hit < 1) { if (IS_IMMORTAL(ch)) ch->hit = 1; else { ch->position = POS_DEAD; handle_death(ch, ch); continue; } } } if (IS_AFFECTED(ch, AFF_PLAGUE) && ch != NULL) { AFFECT_DATA *af, plague; CHAR_DATA *vch; int dam; if (ch->in_room == NULL) continue; act("$n writhes in agony as plague sores erupt from $s skin.", ch, NULL, NULL, TO_ROOM); char_puts("You writhe in agony from the plague.\n", ch); for (af = ch->affected; af != NULL; af = af->next) if (af->type == gsn_plague) break; if (af == NULL) { REMOVE_BIT(ch->affected_by, AFF_PLAGUE); continue; } if (af->level == 1) continue; plague.where = TO_AFFECTS; plague.type = gsn_plague; plague.level = af->level - 1; plague.duration = number_range(1,2 * plague.level); plague.location = APPLY_STR; plague.modifier = -5; plague.bitvector = AFF_PLAGUE; for (vch = ch->in_room->people; vch != NULL; vch = vch->next_in_room) { if (!saves_spell(plague.level + 2, vch, DAM_DISEASE) && !IS_IMMORTAL(vch) && !IS_AFFECTED(vch, AFF_PLAGUE) && number_bits(2) == 0) { char_puts("You feel hot and feverish.\n", vch); act("$n shivers and looks very ill.", vch, NULL, NULL, TO_ROOM); affect_join(vch, &plague); } } dam = UMIN(ch->level, af->level/5 + 1); ch->mana -= dam; ch->move -= dam; damage(ch, ch, dam, gsn_plague, DAM_DISEASE,FALSE); if (number_range(1, 100) < 70) damage(ch, ch, UMAX(ch->max_hit/20, 50), gsn_plague, DAM_DISEASE, TRUE); } else if (IS_AFFECTED(ch, AFF_POISON) && ch != NULL && !IS_AFFECTED(ch, AFF_SLOW)) { AFFECT_DATA *poison; poison = affect_find(ch->affected, gsn_poison); if (poison != NULL) { act("$n shivers and suffers.", ch, NULL, NULL, TO_ROOM); char_puts("You shiver and suffer.\n", ch); damage(ch, ch, poison->level/10 + 1, gsn_poison, DAM_POISON, TRUE); } } else if (ch->position == POS_INCAP && number_range(0, 1) == 0) damage(ch, ch, 1, TYPE_UNDEFINED, DAM_NONE, FALSE); else if (ch->position == POS_MORTAL) damage(ch, ch, 1, TYPE_UNDEFINED, DAM_NONE, FALSE); } /* global for */ /* * Autosave and autoquit. * Check that these chars still exist. */ if (last_save_time == -1 || current_time - last_save_time > 300) { last_save_time = current_time; for (ch = char_list; ch && !IS_NPC(ch); ch = ch_next) { ch_next = ch->next; if (ch->timer > 20) quit_char(ch, 0); else save_char_obj(ch, FALSE); } } } void water_float_update(void) { OBJ_DATA *obj_next; OBJ_DATA *obj; CHAR_DATA *ch; for (obj = object_list; obj != NULL; obj = obj_next) { obj_next = obj->next; if (!obj->in_room || !IS_WATER(obj->in_room)) continue; obj->water_float = obj->water_float > 0 ? obj->water_float - 1 : -1; if (obj->pIndexData->item_type == ITEM_DRINK_CON) { obj->value[1] = URANGE(1, obj->value[1]+8, obj->value[0]); if ((ch = obj->in_room->people)) act("$p makes bubbles on the water.", ch, obj, NULL, TO_ALL); obj->water_float = obj->value[0]-obj->value[1]; obj->value[2] = 0; } if (obj->water_float == 0) { if((ch = obj->in_room->people)) act("$p sinks down the water.", ch, obj, NULL, TO_ALL); extract_obj(obj, 0); } } } void update_obj_affects(OBJ_DATA *obj) { AFFECT_DATA *paf, *paf_next; /* go through affects and decrement */ for (paf = obj->affected; paf != NULL; paf = paf_next) { paf_next = paf->next; if (paf->duration > 0) { paf->duration--; /* spell strength fades with time */ if (number_range(0,4) == 0 && paf->level > 0) paf->level--; } else if (paf->duration == 0) { skill_t *sk; if ((paf_next == NULL || paf_next->type != paf->type || paf_next->duration > 0) && paf->type > 0 && (sk = skill_lookup(paf->type)) && !IS_NULLSTR(sk->msg_obj)) { if (obj->carried_by != NULL) act(sk->msg_obj, obj->carried_by, obj, NULL, TO_CHAR); if (obj->in_room != NULL && obj->in_room->people) act(sk->msg_obj, obj->in_room->people, obj, NULL, TO_ALL); } affect_remove_obj(obj, paf); } } } bool update_ice_obj(OBJ_DATA *obj) { if (obj->carried_by != NULL && obj->carried_by->in_room->sector_type == SECT_DESERT && number_percent() < 40) { act("The extreme heat melts $p.", obj->carried_by, obj, NULL, TO_CHAR); extract_obj(obj, 0); return TRUE; } if (obj->in_room != NULL && obj->in_room->sector_type == SECT_DESERT && number_percent() < 50) { act("The extreme heat melts $p.", obj->in_room->people, obj, NULL, TO_ALL); extract_obj(obj, 0); return TRUE; } return FALSE; } bool update_glass_obj(OBJ_DATA *obj) { if (obj->carried_by && obj->carried_by->in_room->sector_type == SECT_DESERT && !IS_NPC(obj->carried_by) && number_percent() < 20) { act("$p evaporates.", obj->carried_by, obj, NULL, TO_CHAR); extract_obj(obj, 0); return TRUE; } if (obj->in_room && obj->in_room->sector_type == SECT_DESERT && number_percent() < 30) { act("$p evaporates by the extream heat.", obj->in_room->people, obj, NULL, TO_ROOM); act("$p evaporates by the extream heat.", obj->in_room->people, obj, NULL, TO_CHAR); extract_obj(obj, 0); return TRUE; } return FALSE; } void update_pit(OBJ_DATA *obj) { OBJ_DATA *t_obj, *next_obj; static int pit_count = 1; /* more or less an hour */ pit_count = ++pit_count % 120; if (!IS_SET(obj->pIndexData->extra_flags, ITEM_PIT) || pit_count) return; for (t_obj = obj->contains; t_obj; t_obj = next_obj) { next_obj = t_obj->next_content; obj_from_obj(t_obj); extract_obj(t_obj, 0); } } void contents_to_obj(OBJ_DATA *obj, OBJ_DATA *to_obj) { OBJ_DATA *obj_next; for (; obj; obj = obj_next) { obj_next = obj->next_content; obj_from_obj(obj); obj_to_obj(obj, to_obj); } } static inline void save_corpse_contents(OBJ_DATA *corpse) { OBJ_DATA *obj, *obj_next; OBJ_DATA *pit; altar_t *altar; /* in another object */ if (corpse->in_obj) { contents_to_obj(corpse->contains, corpse->in_obj); return; } /* carried by */ if (corpse->carried_by) { for (obj = corpse->contains; obj; obj = obj_next) { obj_next = obj->next_content; obj_from_obj(obj); obj_to_char(obj, corpse->carried_by); } return; } /* pit lookup */ pit = NULL; altar = corpse->altar; for (pit = altar->room->contents; pit; pit = pit->next_content) { if (pit->pIndexData == altar->pit) break; } /* put contents into altar */ if (!pit) { for (obj = corpse->contains; obj; obj = obj_next) { obj_next = obj->next_content; obj_from_obj(obj); obj_to_room(obj, altar->room); } return; } /* put contents into pit */ contents_to_obj(corpse->contains, pit); } void update_one_obj(OBJ_DATA *obj) { OBJ_DATA *t_obj; CHAR_DATA *rch; char *message; update_obj_affects(obj); /* find the uppest obj container */ for(t_obj = obj; t_obj->in_obj; t_obj = t_obj->in_obj) ; if ((t_obj->in_room != NULL && t_obj->in_room->area->nplayer > 0) || (t_obj->carried_by && t_obj->carried_by->in_room && t_obj->carried_by->in_room->area->nplayer > 0)) oprog_call(OPROG_AREA, obj, NULL, NULL); if (check_material(obj, "ice") && update_ice_obj(obj)) return; if (check_material(obj, "glass") && obj->pIndexData->item_type == ITEM_POTION && update_glass_obj(obj)) return; if (obj->condition > -1 && (obj->timer <= 0 || --obj->timer > 0)) return; switch (obj->pIndexData->item_type) { default: message = "$p crumbles into dust."; break; case ITEM_FOUNTAIN: message = "$p dries up."; break; case ITEM_CORPSE_NPC: message = "$p decays into dust."; break; case ITEM_CORPSE_PC: message = "$p decays into dust."; break; case ITEM_FOOD: message = "$p decomposes."; break; case ITEM_POTION: message = "$p has evaporated from disuse."; break; case ITEM_PORTAL: message = "$p fades out of existence."; break; case ITEM_CONTAINER: if (CAN_WEAR(obj, ITEM_WEAR_FLOAT)) if (obj->contains) message = "$p flickers and vanishes, spilling " "its contents on the floor."; else message = "$p flickers and vanishes."; else message = "$p crumbles into dust."; break; } if (obj->carried_by) if (IS_NPC(obj->carried_by) && obj->carried_by->pIndexData->pShop != NULL) obj->carried_by->silver += obj->cost/5; else { act(message, obj->carried_by, obj, NULL, TO_CHAR); if (obj->wear_loc == WEAR_FLOAT) act(message, obj->carried_by, obj, NULL, TO_ROOM); } if (obj->in_room && (rch = obj->in_room->people) && !IS_SET(obj->pIndexData->extra_flags, ITEM_PIT)) act(message, rch, obj, NULL, TO_ALL); if (obj->pIndexData->item_type == ITEM_CORPSE_PC && obj->contains) save_corpse_contents(obj); extract_obj(obj, 0); } OBJ_DATA *last_updated_obj; void obj_update_list(OBJ_DATA *obj) { int i; OBJ_DATA *obj_next; /* some diagnostics */ obj_next = obj; for (i = 0; obj && obj->extracted; obj = obj->next, i++) ; if (i) { log_printf("obj_update_list: skipped %d extracted objs, " "object_list == %p, obj == %p, " "last_updated_obj == %p, " "last_updated_obj->next == %p", i, object_list, obj_next, last_updated_obj, last_updated_obj ? last_updated_obj->next : NULL); } for (; obj; obj = obj_next) { obj_next = obj->next; if (obj->extracted) { obj_update_list(last_updated_obj ? last_updated_obj->next : object_list); return; } update_one_obj(obj); if (!obj->extracted) last_updated_obj = obj; } } /* * Update all objs. * This function is performance sensitive. */ void obj_update(void) { last_updated_obj = NULL; obj_update_list(object_list); } /* * Aggress. * * for each mortal PC * for each mob in room * aggress on some random PC * * This function takes 25% to 35% of ALL Merc cpu time. * Unfortunately, checking on each PC move is too tricky, * because we don't the mob to just attack the first PC * who leads the party into the room. * * -- Furey */ void aggr_update(void) { CHAR_DATA *wch, *wch_next; CHAR_DATA *ch, *ch_next; CHAR_DATA *vch, *vch_next; CHAR_DATA *victim; for (wch = char_list; wch && !IS_NPC(wch); wch = wch_next) { wch_next = wch->next; if (!wch->in_room) continue; if (IS_AWAKE(wch) && IS_AFFECTED(wch, AFF_BLOODTHIRST) && wch->fighting == NULL) { for (vch = wch->in_room->people; vch != NULL && wch->fighting == NULL; vch = vch_next) { vch_next = vch->next_in_room; if (IS_IMMORTAL(vch)) continue; if (wch != vch && can_see(wch,vch) && !is_safe_nomessage(wch,vch)) { act_puts("{RMORE BLOOD! MORE BLOOD! MORE BLOOD!!!{x", wch,NULL,NULL,TO_CHAR,POS_RESTING); do_murder(wch, vch->name); if (JUST_KILLED(wch)) continue; } } } if (wch->level >= LEVEL_IMMORTAL) continue; for (ch = wch->in_room->people; ch; ch = ch_next) { int count; flag64_t act; ch_next = ch->next_in_room; if (!IS_NPC(ch) || (!IS_SET(act = ch->pIndexData->act, ACT_AGGRESSIVE) && ch->last_fought == NULL && ch->target == NULL) || IS_SET(ch->in_room->room_flags, ROOM_PEACE | ROOM_SAFE) || IS_AFFECTED(ch, AFF_CALM) || ch->fighting != NULL || RIDDEN(ch) || IS_AFFECTED(ch, AFF_CHARM) || !IS_AWAKE(ch) || (IS_SET(act, ACT_WIMPY) && IS_AWAKE(wch)) || !can_see(ch, wch) || number_bits(1) == 0 || is_safe_nomessage(ch,wch)) continue; /* Mad mob attacks! */ if (ch->last_fought == wch && !IS_AFFECTED(ch, AFF_SCREAM)) { doprintf(do_yell, ch, "%s! Now you die!", PERS(wch,ch)); wch = check_guard(wch, ch); multi_hit(ch, wch, TYPE_UNDEFINED); continue; } if (ch->target) { if (ch->target == wch) multi_hit(ch, wch, TYPE_UNDEFINED); continue; } if (ch->last_fought) continue; /* * Ok we have a 'wch' player character and a 'ch' npc * aggressor. Now make the aggressor fight a RANDOM * pc victim in the room, giving each 'vch' an equal * chance of selection. */ count = 0; victim = NULL; for (vch = wch->in_room->people; vch != NULL; vch = vch_next) { vch_next = vch->next_in_room; if (!IS_NPC(vch) && vch->level < LEVEL_IMMORTAL && ch->level >= vch->level - 5 && (!IS_SET(act, ACT_WIMPY) || !IS_AWAKE(vch)) && can_see(ch, vch) /* do not attack vampires */ && !HAS_SKILL(vch, gsn_vampire) /* good vs good :( */ && !(IS_GOOD(ch) && IS_GOOD(vch))) { if (number_range(0, count) == 0) victim = vch; count++; } } if (victim == NULL) continue; if (!is_safe_nomessage(ch, victim)) { int dt = TYPE_UNDEFINED; int bs_chance; victim = check_guard(victim, ch); if (get_dam_type(ch, get_eq_char(ch, WEAR_WIELD), &dt) == DAM_PIERCE && (bs_chance = get_skill(ch, gsn_backstab)) && backstab_ok(NULL, victim)) backstab(ch, victim, bs_chance); else multi_hit(ch, victim, TYPE_UNDEFINED); } } } } /* * Handle all kinds of updates. * Called once per pulse from game loop. * Random times to defeat tick-timing clients and players. */ void update_handler(void) { static int pulse_area; static int pulse_mobile; static int pulse_violence; static int pulse_point; static int pulse_music; static int pulse_water_float; static int pulse_raffect; static int pulse_track; if (--pulse_area <= 0) { wiznet("AREA & ROOM TICK!", NULL, NULL, WIZ_TICKS, 0, 0); pulse_area = PULSE_AREA; area_update(); room_update(); do_asave(NULL, "rules"); } if (--pulse_music <= 0) { pulse_music = PULSE_MUSIC; /* song_update(); */ } if (--pulse_mobile <= 0) { pulse_mobile = PULSE_MOBILE; mobile_update(); light_update(); } if (--pulse_violence <= 0) { pulse_violence = PULSE_VIOLENCE; violence_update(); } if (--pulse_water_float <= 0) { pulse_water_float = PULSE_WATER_FLOAT; water_float_update(); } if (--pulse_raffect <= 0) { pulse_raffect = PULSE_RAFFECT; room_affect_update(); } if (--pulse_track <= 0) { pulse_track = PULSE_TRACK; track_update(); } if (--pulse_point <= 0) { CHAR_DATA *ch; wiznet("CHAR TICK!", NULL, NULL, WIZ_TICKS, 0, 0); pulse_point = PULSE_TICK; weather_update(); char_update(); quest_update(); obj_update(); clan_item_update(); check_reboot(); /* room counting */ for (ch = char_list; ch && !IS_NPC(ch); ch = ch->next) if (ch->in_room) ch->in_room->area->count++; } aggr_update(); auction_update(); tail_chain(); return; } void light_update(void) { CHAR_DATA *ch; int dam_light; DESCRIPTOR_DATA *d; for (d = descriptor_list; d != NULL; d = d->next) { if (d->connected != CON_PLAYING) continue; ch = (d->original != NULL) ? d->original : d->character; if (IS_IMMORTAL(ch)) continue; /* also checks vampireness */ if ((dam_light = isn_dark_safe(ch)) == 0) continue; if (dam_light != 2 && number_percent() < get_skill(ch, gsn_light_resistance)) { check_improve(ch, gsn_light_resistance, TRUE, 32); continue; } if (dam_light == 1) char_puts("The light in the room disturbs you.\n", ch); else char_puts("Sun light disturbs you.\n",ch); dam_light = 1 + (ch->max_hit * 4)/ 100; damage(ch, ch, dam_light, TYPE_HUNGER, DAM_LIGHT_V, TRUE); if (ch->position == POS_STUNNED) update_pos(ch); if (number_percent() < 10) gain_condition(ch, COND_DRUNK, -1); } } void room_update(void) { ROOM_INDEX_DATA *room; ROOM_INDEX_DATA *room_next; for (room = top_affected_room; room; room = room_next) { AFFECT_DATA *paf; AFFECT_DATA *paf_next; room_next = room->aff_next; for (paf = room->affected; paf != NULL; paf = paf_next) { paf_next = paf->next; if (paf->duration > 0) { paf->duration--; /* * spell strength shouldn't fade with time * because of checks in safe_rspell with af->level if (number_range(0,4) == 0 && paf->level > 0) paf->level--; */ } else if (paf->duration == 0) affect_remove_room(room, paf); } } } void room_affect_update(void) { ROOM_INDEX_DATA *room; ROOM_INDEX_DATA *room_next; for (room = top_affected_room; room ; room = room_next) { room_next = room->aff_next; while (IS_ROOM_AFFECTED(room, RAFF_PLAGUE) && room->people != NULL) { AFFECT_DATA *af, plague; CHAR_DATA *vch; for (af = room->affected; af != NULL; af = af->next) { if (af->type == gsn_black_death) break; } if (af == NULL) { REMOVE_BIT(room->affected_by,RAFF_PLAGUE); break; } if (af->level == 1) af->level = 2; plague.where = TO_AFFECTS; plague.type = gsn_plague; plague.level = af->level - 1; plague.duration = number_range(1,((plague.level/2)+1)); plague.location = APPLY_NONE; plague.modifier = -5; plague.bitvector = AFF_PLAGUE; for (vch = room->people; vch != NULL; vch = vch->next_in_room) { if (!saves_spell(plague.level ,vch,DAM_DISEASE) && !IS_IMMORTAL(vch) && !is_safe_rspell(af->level,vch) && !IS_AFFECTED(vch,AFF_PLAGUE) && number_bits(3) == 0) { char_puts("You feel hot and feverish.\n",vch); act("$n shivers and looks very ill.",vch,NULL,NULL,TO_ROOM); affect_join(vch,&plague); } } break; } while (IS_ROOM_AFFECTED(room, RAFF_POISON) && room->people != NULL) { AFFECT_DATA *af, paf; CHAR_DATA *vch; for (af = room->affected; af != NULL; af = af->next) { if (af->type == gsn_deadly_venom) break; } if (af == NULL) { REMOVE_BIT(room->affected_by,RAFF_POISON); break; } if (af->level == 1) af->level = 2; paf.where = TO_AFFECTS; paf.type = gsn_poison; paf.level = af->level - 1; paf.duration = number_range(1,((paf.level/5)+1)); paf.location = APPLY_NONE; paf.modifier = -5; paf.bitvector = AFF_POISON; for (vch = room->people; vch != NULL; vch = vch->next_in_room) { if (!saves_spell(paf.level ,vch,DAM_POISON) && !IS_IMMORTAL(vch) && !is_safe_rspell(af->level,vch) && !IS_AFFECTED(vch,AFF_POISON) && number_bits(3) == 0) { char_puts("You feel very sick.\n",vch); act("$n looks very ill.",vch,NULL,NULL,TO_ROOM); affect_join(vch,&paf); } } break; } while (IS_ROOM_AFFECTED(room, RAFF_SLOW) && room->people != NULL) { AFFECT_DATA *af, paf; CHAR_DATA *vch; for (af = room->affected; af != NULL; af = af->next) { if (af->type == gsn_lethargic_mist) break; } if (af == NULL) { REMOVE_BIT(room->affected_by,RAFF_SLOW); break; } if (af->level == 1) af->level = 2; paf.where = TO_AFFECTS; paf.type = gsn_slow; paf.level = af->level - 1; paf.duration = number_range(1,((paf.level/5)+1)); paf.location = APPLY_NONE; paf.modifier = -5; paf.bitvector = AFF_SLOW; for (vch = room->people; vch != NULL; vch = vch->next_in_room) { if (!saves_spell(paf.level ,vch,DAM_OTHER) && !IS_IMMORTAL(vch) && !is_safe_rspell(af->level,vch) && !IS_AFFECTED(vch,AFF_SLOW) && number_bits(3) == 0) { char_puts("You start to move less quickly.\n",vch); act("$n is moving less quickly.",vch,NULL,NULL,TO_ROOM); affect_join(vch,&paf); } } break; } while (IS_ROOM_AFFECTED(room, RAFF_SLEEP) && room->people != NULL) { AFFECT_DATA *af, paf; CHAR_DATA *vch; for (af = room->affected; af != NULL; af = af->next) { if (af->type == gsn_mysterious_dream) break; } if (af == NULL) { REMOVE_BIT(room->affected_by,RAFF_SLEEP); break; } if (af->level == 1) af->level = 2; paf.where = TO_AFFECTS; paf.type = gsn_sleep; paf.level = af->level - 1; paf.duration = number_range(1,((paf.level/10)+1)); paf.location = APPLY_NONE; paf.modifier = -5; paf.bitvector = AFF_SLEEP; for (vch = room->people; vch != NULL; vch = vch->next_in_room) { if (!saves_spell(paf.level - 4,vch,DAM_CHARM) && !IS_IMMORTAL(vch) && !is_safe_rspell(af->level,vch) && !(IS_NPC(vch) && IS_SET(vch->pIndexData->act, ACT_UNDEAD)) && !IS_AFFECTED(vch,AFF_SLEEP) && number_bits(3) == 0) { if (IS_AWAKE(vch)) { char_puts("You feel very sleepy.......zzzzzz.\n",vch); act("$n goes to sleep.",vch,NULL,NULL,TO_ROOM); vch->position = POS_SLEEPING; } affect_join(vch,&paf); } } break; } while (IS_ROOM_AFFECTED(room, RAFF_ESPIRIT) && room->people != NULL) { AFFECT_DATA *af, paf; CHAR_DATA *vch; for (af = room->affected; af != NULL; af = af->next) { if (af->type == gsn_evil_spirit) break; } if (af == NULL) { REMOVE_BIT(room->affected_by,RAFF_ESPIRIT); break; } if (af->level == 1) af->level = 2; paf.where = TO_AFFECTS; paf.type = gsn_evil_spirit; paf.level = af->level; paf.duration = number_range(1,(paf.level/30)); paf.location = APPLY_NONE; paf.modifier = 0; paf.bitvector = 0; for (vch = room->people; vch != NULL; vch = vch->next_in_room) { if (!saves_spell(paf.level + 2,vch,DAM_MENTAL) && !IS_IMMORTAL(vch) && !is_safe_rspell(af->level,vch) && !is_affected(vch,gsn_evil_spirit) && number_bits(3) == 0) { char_puts("You feel worse than ever.\n",vch); act("$n looks more evil.",vch,NULL,NULL,TO_ROOM); affect_join(vch,&paf); } } break; } /* new ones here while (IS_ROOM_AFFECTED(room, RAFF_) && room->people != NULL) { AFFECT_DATA *af, paf; CHAR_DATA *vch; for (af = room->affected; af != NULL; af = af->next) { if (af->type == gsn_) break; } if (af == NULL) { REMOVE_BIT(room->affected_by,RAFF_); break; } if (af->level == 1) af->level = 2; paf.where = TO_AFFECTS; paf.type = gsn_; paf.level = af->level - 1; paf.duration = number_range(1,((paf.level/5)+1)); paf.location = APPLY_NONE; paf.modifier = -5; paf.bitvector = AFF_; for (vch = room->people; vch != NULL; vch = vch->next_in_room) { if (!saves_spell(paf.level + 2,vch,DAM_) && !IS_IMMORTAL(vch) && !is_safe_rspell(af->level,vch) && !IS_AFFECTED(vch,AFF_) && number_bits(3) == 0) { char_puts("You feel hot and feverish.\n",vch); act("$n shivers and looks very ill.",vch,NULL,NULL,TO_ROOM); affect_join(vch,&paf); } } break; } */ } return; } void check_reboot(void) { DESCRIPTOR_DATA *d; switch(reboot_counter) { case -1: break; case 0: reboot_mud(); return; case 1: case 2: case 3: case 4: case 5: case 10: case 15: for (d = descriptor_list; d != NULL; d = d->next) if (d->character != NULL) if (rebooter || !IS_IMMORTAL(d->character)) char_printf(d->character, "{*{W*****{R rEBOOT IN {W%d{R MIN. {W*****{x\n", reboot_counter); else char_printf(d->character, "{*{W*****{R AUTOMAGIC rEBOOT IN {W%d{R MIN. {W*****{x\n", reboot_counter); /* FALLTHRU */ default: reboot_counter--; break; } } void track_update(void) { CHAR_DATA *ch, *ch_next; for (ch = npc_list; ch; ch = ch_next) { CHAR_DATA *vch, *vch_next; ch_next = ch->next; if (IS_AFFECTED(ch, AFF_CALM | AFF_CHARM) || ch->fighting || !ch->in_room || !IS_AWAKE(ch) || IS_SET(ch->pIndexData->act, ACT_NOTRACK) || RIDDEN(ch) || IS_AFFECTED(ch, AFF_SCREAM)) continue; if (ch->last_fought != NULL && ch->in_room != ch->last_fought->in_room) { do_track(ch, ch->last_fought->name); continue; } if (ch->in_mind == NULL) continue; for (vch = ch->in_room->people; vch; vch = vch_next) { vch_next = vch->next_in_room; if (IS_IMMORTAL(vch) || !can_see(ch,vch) || is_safe_nomessage(ch,vch) || !is_name(vch->name,ch->in_mind)) continue; doprintf(do_yell, ch, "So we meet again, %s", vch->name); do_murder(ch, vch->name); } } } void clan_item_update(void) { clan_t *clan; OBJ_DATA *obj; bool put_back; int i; int j; if (time_info.hour != 0) return; for (i=0; i<clans.nused; i++) { put_back = FALSE; if ((clan=clan_lookup(i))->obj_ptr == NULL) continue; for (obj=clan->obj_ptr; obj->in_obj; obj=obj->in_obj); if (obj->carried_by) put_back = TRUE; else if (obj->in_room) for(j=0; j<clans.nused; j++) if (!(put_back=(obj->in_room->vnum != clan_lookup(j)->altar_vnum))) break; if(put_back) { if(clan->obj_ptr->in_obj) obj_from_obj(clan->obj_ptr); if(clan->obj_ptr->carried_by) obj_from_char(clan->obj_ptr); if(clan->obj_ptr->in_room) obj_from_room(clan->obj_ptr); if(clan->altar_ptr) obj_to_obj(clan->obj_ptr, clan->altar_ptr); else bug("clan_item_update: no altar_ptr for clan %d", i); } } }