/** * Go down one level */ void do_cmd_go_down(struct command *cmd) { int descend_to = dungeon_get_next_level(player->depth, 1); /* Verify stairs */ if (!square_isdownstairs(cave, player->py, player->px)) { msg("I see no down staircase here."); return; } /* Paranoia, no descent from z_info->max_depth - 1 */ if (player->depth == z_info->max_depth - 1) { msg("The dungeon does not appear to extend deeper"); return; } /* Warn a force_descend player if they're going to a quest level */ if (OPT(birth_force_descend)) { descend_to = dungeon_get_next_level(player->max_depth, 1); if (is_quest(descend_to) && !get_check("Are you sure you want to descend?")) return; } /* Hack -- take a turn */ player->upkeep->energy_use = z_info->move_energy; /* Success */ msgt(MSG_STAIRS_DOWN, "You enter a maze of down staircases."); /* Create a way back */ player->upkeep->create_up_stair = true; player->upkeep->create_down_stair = false; /* Change level */ dungeon_change_level(descend_to); }
/** * Go up one level */ void do_cmd_go_up(struct command *cmd) { int ascend_to; /* Verify stairs */ if (!square_isupstairs(cave, player->py, player->px)) { msg("I see no up staircase here."); return; } /* Force descend */ if (OPT(birth_force_descend)) { msg("Nothing happens!"); return; } ascend_to = dungeon_get_next_level(player->depth, -1); if (ascend_to == player->depth) { msg("You can't go up from here!"); return; } /* Take a turn */ player->upkeep->energy_use = z_info->move_energy; /* Success */ msgt(MSG_STAIRS_UP, "You enter a maze of up staircases."); /* Create a way back */ player->upkeep->create_up_stair = false; player->upkeep->create_down_stair = true; /* Change level */ dungeon_change_level(ascend_to); }
/** * Handle things that need updating once every 10 game turns */ void process_world(struct chunk *c) { int i, y, x; /* Compact the monster list if we're approaching the limit */ if (cave_monster_count(cave) + 32 > z_info->level_monster_max) compact_monsters(64); /* Too many holes in the monster list - compress */ if (cave_monster_count(cave) + 32 < cave_monster_max(cave)) compact_monsters(0); /*** Check the Time ***/ /* Play an ambient sound at regular intervals. */ if (!(turn % ((10L * z_info->day_length) / 4))) play_ambient_sound(); /*** Handle stores and sunshine ***/ if (!player->depth) { /* Daybreak/Nighfall in town */ if (!(turn % ((10L * z_info->day_length) / 2))) { bool dawn; /* Check for dawn */ dawn = (!(turn % (10L * z_info->day_length))); /* Day breaks */ if (dawn) msg("The sun has risen."); /* Night falls */ else msg("The sun has fallen."); /* Illuminate */ cave_illuminate(c, dawn); } } else { /* Update the stores once a day (while in the dungeon). The changes are not actually made until return to town, to avoid giving details away in the knowledge menu. */ if (!(turn % (10L * z_info->store_turns))) daycount++; } /* Check for creature generation */ if (one_in_(z_info->alloc_monster_chance)) (void)pick_and_place_distant_monster(cave, player, z_info->max_sight + 5, true, player->depth); /*** Damage over Time ***/ /* Take damage from poison */ if (player->timed[TMD_POISONED]) take_hit(player, 1, "poison"); /* Take damage from cuts */ if (player->timed[TMD_CUT]) { /* Mortal wound or Deep Gash */ if (player->timed[TMD_CUT] > TMD_CUT_SEVERE) i = 3; /* Severe cut */ else if (player->timed[TMD_CUT] > TMD_CUT_NASTY) i = 2; /* Other cuts */ else i = 1; /* Take damage */ take_hit(player, i, "a fatal wound"); } /*** Check the Food, and Regenerate ***/ /* Digest normally */ if (!(turn % 100)) { /* Basic digestion rate based on speed */ i = turn_energy(player->state.speed) * 2; /* Regeneration takes more food */ if (player_of_has(player, OF_REGEN)) i += 30; /* Slow digestion takes less food */ if (player_of_has(player, OF_SLOW_DIGEST)) i /= 5; /* Minimal digestion */ if (i < 1) i = 1; /* Digest some food */ player_set_food(player, player->food - i); } /* Getting Faint */ if (player->food < PY_FOOD_FAINT) { /* Faint occasionally */ if (!player->timed[TMD_PARALYZED] && one_in_(10)) { /* Message */ msg("You faint from the lack of food."); disturb(player, 1); /* Faint (bypass free action) */ (void)player_inc_timed(player, TMD_PARALYZED, 1 + randint0(5), true, false); } } /* Starve to death (slowly) */ if (player->food < PY_FOOD_STARVE) { /* Calculate damage */ i = (PY_FOOD_STARVE - player->food) / 10; /* Take damage */ take_hit(player, i, "starvation"); } /* Regenerate Hit Points if needed */ if (player->chp < player->mhp) player_regen_hp(player); /* Regenerate mana if needed */ if (player->csp < player->msp) player_regen_mana(player); /* Timeout various things */ decrease_timeouts(); /* Process light */ player_update_light(player); /*** Process Inventory ***/ /* Handle experience draining */ if (player_of_has(player, OF_DRAIN_EXP)) { if ((player->exp > 0) && one_in_(10)) { s32b d = damroll(10, 6) + (player->exp / 100) * z_info->life_drain_percent; player_exp_lose(player, d / 10, false); } equip_learn_flag(player, OF_DRAIN_EXP); } /* Recharge activatable objects and rods */ recharge_objects(); /* Notice things after time */ if (!(turn % 100)) equip_learn_after_time(player); /* Decrease trap timeouts */ for (y = 0; y < cave->height; y++) { for (x = 0; x < cave->width; x++) { struct trap *trap = cave->squares[y][x].trap; while (trap) { if (trap->timeout) { trap->timeout--; if (!trap->timeout) square_light_spot(cave, y, x); } trap = trap->next; } } } /*** Involuntary Movement ***/ /* Delayed Word-of-Recall */ if (player->word_recall) { /* Count down towards recall */ player->word_recall--; /* Activate the recall */ if (!player->word_recall) { /* Disturbing! */ disturb(player, 0); /* Determine the level */ if (player->depth) { msgt(MSG_TPLEVEL, "You feel yourself yanked upwards!"); dungeon_change_level(player, 0); } else { msgt(MSG_TPLEVEL, "You feel yourself yanked downwards!"); /* Force descent to a lower level if allowed */ if (OPT(player, birth_force_descend) && player->max_depth < z_info->max_depth - 1 && !is_quest(player->max_depth)) { player->max_depth = dungeon_get_next_level(player->max_depth, 1); } /* New depth - back to max depth or 1, whichever is deeper */ dungeon_change_level(player, player->max_depth < 1 ? 1: player->max_depth); } } } /* Delayed Deep Descent */ if (player->deep_descent) { /* Count down towards recall */ player->deep_descent--; /* Activate the recall */ if (player->deep_descent == 0) { int target_increment; int target_depth = player->max_depth; /* Calculate target depth */ target_increment = (4 / z_info->stair_skip) + 1; target_depth = dungeon_get_next_level(player->max_depth, target_increment); disturb(player, 0); /* Determine the level */ if (target_depth > player->depth) { msgt(MSG_TPLEVEL, "The floor opens beneath you!"); dungeon_change_level(player, target_depth); } else { /* Otherwise do something disastrous */ msgt(MSG_TPLEVEL, "You are thrown back in an explosion!"); effect_simple(EF_DESTRUCTION, "0", 0, 5, 0, NULL); } } } }
/** * Hit a trap. */ extern void hit_trap(int y, int x) { bool ident = false; struct trap *trap; struct effect *effect; /* Count the hidden traps here */ int num = num_traps(cave, y, x, -1); /* The player is safe from all traps */ if (player_is_trapsafe(player)) return; /* Oops. We've walked right into trouble. */ if (num == 1) msg("You stumble upon a trap!"); else if (num > 1) msg("You stumble upon some traps!"); /* Look at the traps in this grid */ for (trap = square_trap(cave, y, x); trap; trap = trap->next) { int flag; bool saved = false; /* Require that trap be capable of affecting the character */ if (!trf_has(trap->kind->flags, TRF_TRAP)) continue; if (trap->timeout) continue; /* Disturb the player */ disturb(player, 0); /* Give a message */ if (trap->kind->msg) msg(trap->kind->msg); /* Test for save due to flag */ for (flag = of_next(trap->kind->save_flags, FLAG_START); flag != FLAG_END; flag = of_next(trap->kind->save_flags, flag + 1)) if (player_of_has(player, flag)) { saved = true; equip_learn_flag(player, flag); } /* Test for save due to armor */ if (trf_has(trap->kind->flags, TRF_SAVE_ARMOR) && !trap_check_hit(125)) saved = true; /* Test for save due to saving throw */ if (trf_has(trap->kind->flags, TRF_SAVE_THROW) && (randint0(100) < player->state.skills[SKILL_SAVE])) saved = true; /* Save, or fire off the trap */ if (saved) { if (trap->kind->msg_good) msg(trap->kind->msg_good); } else { if (trap->kind->msg_bad) msg(trap->kind->msg_bad); effect = trap->kind->effect; effect_do(effect, source_trap(trap), NULL, &ident, false, 0, 0, 0); /* Do any extra effects */ if (trap->kind->effect_xtra && one_in_(2)) { if (trap->kind->msg_xtra) msg(trap->kind->msg_xtra); effect = trap->kind->effect_xtra; effect_do(effect, source_trap(trap), NULL, &ident, false, 0, 0, 0); } } /* Some traps drop you a dungeon level */ if (trf_has(trap->kind->flags, TRF_DOWN)) dungeon_change_level(player, dungeon_get_next_level(player->depth, 1)); /* Some traps drop you onto them */ if (trf_has(trap->kind->flags, TRF_PIT)) monster_swap(player->py, player->px, trap->fy, trap->fx); /* Some traps disappear after activating, all have a chance to */ if (trf_has(trap->kind->flags, TRF_ONETIME) || one_in_(3)) { square_destroy_trap(cave, y, x); square_forget(cave, y, x); } /* Trap may have gone */ if (!square_trap(cave, y, x)) break; /* Trap becomes visible (always XXX) */ trf_on(trap->flags, TRF_VISIBLE); square_memorize(cave, y, x); } /* Verify traps (remove marker if appropriate) */ (void)square_verify_trap(cave, y, x, 0); }