Exemplo n.º 1
0
/**
 * Housekeeping on leaving a level
 */
static void on_leave_level(void) {
	/* Any pending processing */
	notice_stuff(player);
	update_stuff(player);
	redraw_stuff(player);

	/* Flush messages */
	event_signal(EVENT_MESSAGE_FLUSH);
}
Exemplo n.º 2
0
/**
 * Overflow an item from the pack, if it is overfull.
 */
void pack_overflow(struct object *obj)
{
	int i;
	char o_name[80];
	bool artifact = false;

	if (!pack_is_overfull()) return;

	/* Disturbing */
	disturb(player, 0);

	/* Warning */
	msg("Your pack overflows!");

	/* Get the last proper item */
	for (i = 1; i <= z_info->pack_size; i++)
		if (!player->upkeep->inven[i])
			break;

	/* Drop the last inventory item unless requested otherwise */
	if (!obj) {
		obj = player->upkeep->inven[i - 1];
	}

	/* Rule out weirdness (like pack full, but inventory empty) */
	assert(obj != NULL);

	/* Describe */
	object_desc(o_name, sizeof(o_name), obj, ODESC_PREFIX | ODESC_FULL);
	if (obj->artifact) {
		artifact = true;
	}

	/* Message */
	msg("You drop %s.", o_name);

	/* Excise the object and drop it (carefully) near the player */
	gear_excise_object(obj);
	drop_near(cave, &obj, 0, player->py, player->px, false);

	/* Describe */
	if (artifact)
		msg("You no longer have the %s.", o_name);
	else
		msg("You no longer have %s.", o_name);

	/* Notice, update, redraw */
	if (player->upkeep->notice) notice_stuff(player);
	if (player->upkeep->update) update_stuff(player);
	if (player->upkeep->redraw) redraw_stuff(player);
}
Exemplo n.º 3
0
/**
 * Overflow an item from the pack, if it is overfull.
 */
void pack_overflow(void)
{
	int i;
	struct object *obj = NULL;
	char o_name[80];

	if (!pack_is_overfull()) return;

	/* Disturbing */
	disturb(player, 0);

	/* Warning */
	msg("Your pack overflows!");

	/* Find the last inventory item */
	for (i = 1; i <= z_info->pack_size; i++)
		if (!player->upkeep->inven[i])
			break;

	/* Last object was the previous index */
	obj = player->upkeep->inven[i - 1];

	/* Rule out weirdness (like pack full, but inventory empty) */
	assert(obj != NULL);

	/* Describe */
	object_desc(o_name, sizeof(o_name), obj, ODESC_PREFIX | ODESC_FULL);

	/* Message */
	msg("You drop %s (%c).", o_name, I2A(i - 1));

	/* Excise the object and drop it (carefully) near the player */
	gear_excise_object(obj);
	drop_near(cave, obj, 0, player->py, player->px, FALSE);

	/* Describe */
	if (obj->artifact)
		msg("You no longer have the %s (%c).", o_name, I2A(i - 1));
	else
		msg("You no longer have %s (%c).", o_name, I2A(i - 1));

	/* Notice stuff (if needed) */
	if (player->upkeep->notice) notice_stuff(player->upkeep);

	/* Update stuff (if needed) */
	if (player->upkeep->update) update_stuff(player->upkeep);

	/* Redraw stuff (if needed) */
	if (player->upkeep->redraw) redraw_stuff(player->upkeep);
}
Exemplo n.º 4
0
/**
 * Housekeeping on arriving on a new level
 */
void on_new_level(void)
{
	/* Play ambient sound on change of level. */
	play_ambient_sound();

	/* Cancel the target */
	target_set_monster(0);

	/* Cancel the health bar */
	health_track(player->upkeep, NULL);

	/* Disturb */
	disturb(player, 1);

	/* Track maximum player level */
	if (player->max_lev < player->lev)
		player->max_lev = player->lev;

	/* Track maximum dungeon level */
	if (player->max_depth < player->depth)
		player->max_depth = player->depth;

	/* Flush messages */
	event_signal(EVENT_MESSAGE_FLUSH);

	/* Update display */
	event_signal(EVENT_NEW_LEVEL_DISPLAY);

	/* Update player */
	update_player_object_knowledge(player);
	player->upkeep->update |= (PU_BONUS | PU_HP | PU_SPELLS | PU_INVEN);
	player->upkeep->notice |= (PN_COMBINE | PN_SEARCH);
	notice_stuff(player);
	update_stuff(player);
	redraw_stuff(player);

	/* Refresh */
	event_signal(EVENT_REFRESH);

	/* Announce (or repeat) the feeling */
	if (player->depth)
		display_feeling(false);

	/* Give player minimum energy to start a new level, but do not reduce
	 * higher value from savefile for level in progress */
	if (player->energy < z_info->move_energy)
		player->energy = z_info->move_energy;
}
Exemplo n.º 5
0
/**
 * The main game loop.
 *
 * This function will run until the player needs to enter a command, or closes
 * the game, or the character dies.
 */
void run_game_loop(void)
{
	/* Tidy up after the player's command */
	process_player_cleanup();

	/* Keep processing the player until they use some energy or
	 * another command is needed */
	while (player->upkeep->playing) {
		process_player();
		if (player->upkeep->energy_use)
			break;
		else
			return;
	}

	/* The player may still have enough energy to move, so we run another
	 * player turn before processing the rest of the world */
	while (player->energy >= z_info->move_energy) {
		/* Do any necessary animations */
		event_signal(EVENT_ANIMATE);
		
		/* Process monster with even more energy first */
		process_monsters(cave, player->energy + 1);
		if (player->is_dead || !player->upkeep->playing ||
			player->upkeep->generate_level)
			break;

		/* Process the player until they use some energy */
		while (player->upkeep->playing) {
			process_player();
			if (player->upkeep->energy_use)
				break;
			else
				return;
		}
	}

	/* Now that the player's turn is fully complete, we run the main loop 
	 * until player input is needed again */
	while (true) {
		notice_stuff(player);
		handle_stuff(player);
		event_signal(EVENT_REFRESH);

		/* Process the rest of the world, give the player energy and 
		 * increment the turn counter unless we need to stop playing or
		 * generate a new level */
		if (player->is_dead || !player->upkeep->playing)
			return;
		else if (!player->upkeep->generate_level) {
			/* Process the rest of the monsters */
			process_monsters(cave, 0);

			/* Mark all monsters as ready to act when they have the energy */
			reset_monsters();

			/* Refresh */
			notice_stuff(player);
			handle_stuff(player);
			event_signal(EVENT_REFRESH);
			if (player->is_dead || !player->upkeep->playing)
				return;

			/* Process the world every ten turns */
			if (!(turn % 10) && !player->upkeep->generate_level) {
				process_world(cave);

				/* Refresh */
				notice_stuff(player);
				handle_stuff(player);
				event_signal(EVENT_REFRESH);
				if (player->is_dead || !player->upkeep->playing)
					return;
			}

			/* Give the player some energy */
			player->energy += turn_energy(player->state.speed);

			/* Count game turns */
			turn++;
		}

		/* Make a new level if requested */
		if (player->upkeep->generate_level) {
			if (character_dungeon)
				on_leave_level();

			cave_generate(&cave, player);
			on_new_level();

			player->upkeep->generate_level = false;
		}

		/* If the player has enough energy to move they now do so, after
		 * any monsters with more energy take their turns */
		while (player->energy >= z_info->move_energy) {
			/* Do any necessary animations */
			event_signal(EVENT_ANIMATE);

			/* Process monster with even more energy first */
			process_monsters(cave, player->energy + 1);
			if (player->is_dead || !player->upkeep->playing ||
				player->upkeep->generate_level)
				break;

			/* Process the player until they use some energy */
			while (player->upkeep->playing) {
				process_player();
				if (player->upkeep->energy_use)
					break;
				else
					return;
			}
		}
	}
}
Exemplo n.º 6
0
/**
 * Process player commands from the command queue, finishing when there is a
 * command using energy (any regular game command), or we run out of commands
 * and need another from the user, or the character changes level or dies, or
 * the game is stopped.
 *
 * Notice the annoying code to handle "pack overflow", which
 * must come first just in case somebody manages to corrupt
 * the savefiles by clever use of menu commands or something. (Can go? NRM)
 *
 * Notice the annoying code to handle "monster memory" changes,
 * which allows us to avoid having to update the window flags
 * every time we change any internal monster memory field, and
 * also reduces the number of times that the recall window must
 * be redrawn.
 */
void process_player(void)
{
	/* Check for interrupts */
	player_resting_complete_special(player);
	event_signal(EVENT_CHECK_INTERRUPT);

	/* Repeat until energy is reduced */
	do {
		/* Refresh */
		notice_stuff(player);
		handle_stuff(player);
		event_signal(EVENT_REFRESH);

		/* Hack -- Pack Overflow */
		pack_overflow(NULL);

		/* Assume free turn */
		player->upkeep->energy_use = 0;

		/* Dwarves detect treasure */
		if (player_has(player, PF_SEE_ORE)) {
			/* Only if they are in good shape */
			if (!player->timed[TMD_IMAGE] &&
				!player->timed[TMD_CONFUSED] &&
				!player->timed[TMD_AMNESIA] &&
				!player->timed[TMD_STUN] &&
				!player->timed[TMD_PARALYZED] &&
				!player->timed[TMD_TERROR] &&
				!player->timed[TMD_AFRAID])
				effect_simple(EF_DETECT_GOLD, "3d3", 1, 0, 0, NULL);
		}

		/* Paralyzed or Knocked Out player gets no turn */
		if ((player->timed[TMD_PARALYZED]) || (player->timed[TMD_STUN] >= 100))
			cmdq_push(CMD_SLEEP);

		/* Prepare for the next command */
		if (cmd_get_nrepeats() > 0)
			event_signal(EVENT_COMMAND_REPEAT);
		else {
			/* Check monster recall */
			if (player->upkeep->monster_race)
				player->upkeep->redraw |= (PR_MONSTER);

			/* Place cursor on player/target */
			event_signal(EVENT_REFRESH);
		}

		/* Get a command from the queue if there is one */
		if (!cmdq_pop(CMD_GAME))
			break;

		if (!player->upkeep->playing)
			break;

		process_player_cleanup();
	} while (!player->upkeep->energy_use &&
			 !player->is_dead &&
			 !player->upkeep->generate_level);

	/* Notice stuff (if needed) */
	notice_stuff(player);
}
Exemplo n.º 7
0
/**
 * Decreases a monster's hit points by `dam` and handle monster death.
 *
 * Hack -- we "delay" fear messages by passing around a "fear" flag.
 *
 * We announce monster death (using an optional "death message" (`note`)
 * if given, and a otherwise a generic killed/destroyed message).
 * 
 * Returns true if the monster has been killed (and deleted).
 *
 * TODO: Consider decreasing monster experience over time, say, by using
 * "(m_exp * m_lev * (m_lev)) / (p_lev * (m_lev + n_killed))" instead
 * of simply "(m_exp * m_lev) / (p_lev)", to make the first monster
 * worth more than subsequent monsters.  This would also need to
 * induce changes in the monster recall code.  XXX XXX XXX
 **/
bool mon_take_hit(struct monster *mon, int dam, bool *fear, const char *note)
{
	s32b div, new_exp, new_exp_frac;
	struct monster_lore *lore = get_lore(mon->race);


	/* Redraw (later) if needed */
	if (player->upkeep->health_who == mon)
		player->upkeep->redraw |= (PR_HEALTH);

	/* Wake it up */
	mon_clear_timed(mon, MON_TMD_SLEEP, MON_TMD_FLG_NOMESSAGE, false);

	/* Become aware of its presence */
	if (mflag_has(mon->mflag, MFLAG_UNAWARE))
		become_aware(mon);

	/* Hurt it */
	mon->hp -= dam;

	/* It is dead now */
	if (mon->hp < 0) {
		char m_name[80];
		char buf[80];

		/* Assume normal death sound */
		int soundfx = MSG_KILL;

		/* Play a special sound if the monster was unique */
		if (rf_has(mon->race->flags, RF_UNIQUE)) {
			if (mon->race->base == lookup_monster_base("Morgoth"))
				soundfx = MSG_KILL_KING;
			else
				soundfx = MSG_KILL_UNIQUE;
		}

		/* Extract monster name */
		monster_desc(m_name, sizeof(m_name), mon, MDESC_DEFAULT);

		/* Death message */
		if (note) {
			if (strlen(note) <= 1) {
				/* Death by Spell attack - messages handled by project_m() */
			} else {
				char *str = format("%s%s", m_name, note);
				my_strcap(str);

				/* Make sure to flush any monster messages first */
				notice_stuff(player);

				/* Death by Missile attack */
				msgt(soundfx, "%s", str);
			}
		} else {
			/* Make sure to flush any monster messages first */
			notice_stuff(player);

			if (!mflag_has(mon->mflag, MFLAG_VISIBLE))
				/* Death by physical attack -- invisible monster */
				msgt(soundfx, "You have killed %s.", m_name);
			else if (monster_is_unusual(mon->race))
				/* Death by Physical attack -- non-living monster */
				msgt(soundfx, "You have destroyed %s.", m_name);
			else
				/* Death by Physical attack -- living monster */
				msgt(soundfx, "You have slain %s.", m_name);
		}

		/* Player level */
		div = player->lev;

		/* Give some experience for the kill */
		new_exp = ((long)mon->race->mexp * mon->race->level) / div;

		/* Handle fractional experience */
		new_exp_frac = ((((long)mon->race->mexp * mon->race->level) % div)
		                * 0x10000L / div) + player->exp_frac;

		/* Keep track of experience */
		if (new_exp_frac >= 0x10000L) {
			new_exp++;
			player->exp_frac = (u16b)(new_exp_frac - 0x10000L);
		} else
			player->exp_frac = (u16b)new_exp_frac;

		/* When the player kills a Unique, it stays dead */
		if (rf_has(mon->race->flags, RF_UNIQUE)) {
			char unique_name[80];
			mon->race->max_num = 0;

			/* 
			 * This gets the correct name if we slay an invisible 
			 * unique and don't have See Invisible.
			 */
			monster_desc(unique_name, sizeof(unique_name), mon,
						 MDESC_DIED_FROM);

			/* Log the slaying of a unique */
			strnfmt(buf, sizeof(buf), "Killed %s", unique_name);
			history_add(buf, HIST_SLAY_UNIQUE, 0);
		}

		/* Gain experience */
		player_exp_gain(player, new_exp);

		/* Generate treasure */
		monster_death(mon, false);

		/* Recall even invisible uniques or winners */
		if (mflag_has(mon->mflag, MFLAG_VISIBLE) ||
			rf_has(mon->race->flags, RF_UNIQUE)) {
			/* Count kills this life */
			if (lore->pkills < SHRT_MAX) lore->pkills++;

			/* Count kills in all lives */
			if (lore->tkills < SHRT_MAX) lore->tkills++;

			/* Update lore and tracking */
			lore_update(mon->race, lore);
			monster_race_track(player->upkeep, mon->race);
		}

		/* Delete the monster */
		delete_monster_idx(mon->midx);

		/* Not afraid */
		(*fear) = false;

		/* Monster is dead */
		return (true);
	}


	/* Mega-Hack -- Pain cancels fear */
	if (!(*fear) && mon->m_timed[MON_TMD_FEAR] && (dam > 0)) {
		int tmp = randint1(dam);

		/* Cure a little or all fear */
		if (tmp < mon->m_timed[MON_TMD_FEAR]) {
			/* Reduce fear */
			mon_dec_timed(mon, MON_TMD_FEAR, tmp, MON_TMD_FLG_NOMESSAGE,
				false);
		} else {
			/* Cure fear */
			mon_clear_timed(mon, MON_TMD_FEAR, MON_TMD_FLG_NOMESSAGE, false);

			/* No more fear */
			(*fear) = false;
		}
	}

	/* Sometimes a monster gets scared by damage */
	if (!mon->m_timed[MON_TMD_FEAR] && 
		!rf_has(mon->race->flags, RF_NO_FEAR) &&	dam > 0) {
		int percentage;

		/* Percentage of fully healthy */
		percentage = (100L * mon->hp) / mon->maxhp;

		/*
		 * Run (sometimes) if at 10% or less of max hit points,
		 * or (usually) when hit for half its current hit points
		 */
		if ((randint1(10) >= percentage) ||
		    ((dam >= mon->hp) && (randint0(100) < 80))) {
			int timer = randint1(10) + (((dam >= mon->hp) && (percentage > 7))
										? 20 : ((11 - percentage) * 5));

			/* Hack -- note fear */
			(*fear) = true;

			mon_inc_timed(mon, MON_TMD_FEAR, timer,
					MON_TMD_FLG_NOMESSAGE | MON_TMD_FLG_NOFAIL, false);
		}
	}


	/* Not dead yet */
	return (false);
}
Exemplo n.º 8
0
/**
 * Handle character death
 */
void death_screen(void)
{
    const region area = { 51, 2, 0, N_ELEMENTS(death_actions) };

    /* Dump bones file */
    make_bones();

    /* Handle retirement */
    if (p_ptr->total_winner)
	kingly();

    /* Save dead player */
    if (!old_save())
    {
	msg_print("death save failed!");
	message_flush();
    }

    /* Get time of death */
#ifdef _WIN32_WCE
    {
	unsigned long fake_time(unsigned long *fake_time_t);
	fake_time(&death_time);
    }
#else
    (void) time(&death_time);
#endif

    /* Hack - Know everything upon death */
    death_knowledge();

    event_signal(EVENT_INVENTORY);
    event_signal(EVENT_EQUIPMENT);

    /* Handle stuff */
    notice_stuff();
    handle_stuff();

    /* You are dead */
    print_tomb();

    /* Enter player in high score list */
    enter_score(&death_time);

    /* Flush all input keys */
    flush();

    /* Flush messages */
    msg_print(NULL);

    if (!death_menu)
    {
	death_menu = menu_new_action(death_actions,
				     N_ELEMENTS(death_actions));

	death_menu->flags = MN_CASELESS_TAGS;
    }

    menu_layout(death_menu, &area);

    do
    {
	menu_select(death_menu, 0);
    } while (!get_check("Do you want to quit? "));
}