Esempio n. 1
0
void
look(int wakeup)
{
    int     x, y;
    char   ch, och;
    int  oldx, oldy;
    int inpass, horizontal, vertical, do_light = FALSE, do_blank = FALSE;
    int passcount = 0;
    struct room *rp;
    int ey, ex;

    /* Are we moving vertically or horizontally? */

    if (runch == 'h' || runch == 'l')
        horizontal = TRUE;
    else
        horizontal = FALSE;

    if (runch == 'j' || runch == 'k')
        vertical = TRUE;
    else
        vertical = FALSE;

    getyx(cw, oldy, oldx);  /* Save current position */

    /*
     * Blank out the floor around our last position and check for moving
     * out of a corridor in a maze.
    */

    if (oldrp != NULL && (oldrp->r_flags & ISDARK) &&
            !(oldrp->r_flags & HASFIRE) && off(player, ISBLIND))
        do_blank = TRUE;

    for (x = player.t_oldpos.x - 1; x <= player.t_oldpos.x + 1; x++)
        for (y = player.t_oldpos.y - 1; y <= player.t_oldpos.y + 1;
                y++)
        {
            ch = show(y, x);

            if (do_blank && (y != hero.y || x != hero.x) && ch == FLOOR)
                mvwaddch(cw, y, x, ' ');

            /* Moving out of a corridor? */

            if (levtype == MAZELEV &&
                    (ch != '|' && ch != '-') && /* Not a wall */
                    ((vertical && x != player.t_oldpos.x &&
                      y == player.t_oldpos.y) ||
                     (horizontal && y != player.t_oldpos.y &&
                      x == player.t_oldpos.x)))
                do_light = TRUE;    /* Just came to a turn */
        }

    inpass = ((rp = roomin(hero)) == NULL);    /* Are we in a passage? */

    /* Are we coming out of a wall into a corridor in a maze? */
    och = show(player.t_oldpos.y, player.t_oldpos.x);
    ch = show(hero.y, hero.x);

    if (levtype == MAZELEV && (och == '|' || och == '-' ||
                               och == SECRETDOOR) && (ch != '|' && ch != '-' && ch != SECRETDOOR))
    {
        do_light = off(player, ISBLIND);    /* Light it up if not blind */
    }

    /* Look around the player */

    ey = hero.y + 1;
    ex = hero.x + 1;

    for (x = hero.x - 1; x <= ex; x++)
        if (x >= 0 && x < COLS)
            for (y = hero.y - 1; y <= ey; y++)
            {
                if (y <= 0 || y >= LINES - 2)
                    continue;

                if (isalpha(mvwinch(mw, y, x)))
                {
                    struct linked_list  *it;
                    struct thing    *tp;

                    if (wakeup)
                        it = wake_monster(y, x);
                    else
                        it = find_mons(y, x);

                    if (it == NULL)
                        continue;

                    tp = THINGPTR(it);
                    tp->t_oldch = CCHAR( mvinch(y, x) );

                    if (isatrap(tp->t_oldch))
                    {
                        struct trap *trp = trap_at(y, x);

                        tp->t_oldch = (trp->tr_flags & ISFOUND) ? tp->t_oldch
                                      : trp->tr_show;
                    }

                    if (tp->t_oldch == FLOOR &&
                            (rp->r_flags & ISDARK)
                            && !(rp->r_flags & HASFIRE) &&
                            off(player, ISBLIND))
                        tp->t_oldch = ' ';
                }

                /* Secret doors show as walls */

                if ((ch = show(y, x)) == SECRETDOOR)
                    ch = secretdoor(y, x);

                /*
                 * Don't show room walls if he is in a
                 * passage and check for maze turns
                */

                if (off(player, ISBLIND))
                {
                    if (y == hero.y && x == hero.x || (inpass && (ch == '-' ||
                                                       ch == '|')))
                        continue;

                    /* Are we at a crossroads in a maze? */

                    if (levtype == MAZELEV && (ch != '|' && ch != '-') &&
                            /* Not a wall */
                            ((vertical && x != hero.x && y == hero.y) ||
                             (horizontal && y != hero.y && x == hero.x)))
                        do_light = TRUE;
                    /* Just came to a turn */
                }
                else if (y != hero.y || x != hero.x)
                    continue;

                wmove(cw, y, x);
                waddch(cw, ch);

                if (door_stop && !firstmove && running)
                {
                    switch (runch)
                    {
                    case 'h':
                        if (x == ex)
                            continue;
                        break;
                    case 'j':
                        if (y == hero.y - 1)
                            continue;
                        break;
                    case 'k':
                        if (y == ey)
                            continue;
                        break;
                    case 'l':
                        if (x == hero.x - 1)
                            continue;
                        break;
                    case 'y':
                        if ((x + y) - (hero.x + hero.y) >= 1)
                            continue;
                        break;
                    case 'u':
                        if ((y - x) - (hero.y - hero.x) >= 1)
                            continue;
                        break;
                    case 'n':
                        if ((x + y) - (hero.x + hero.y) <= -1)
                            continue;
                        break;
                    case 'b':
                        if ((y - x) - (hero.y - hero.x) <= -1)
                            continue;
                        break;
                    }

                    switch (ch)
                    {
                    case DOOR:
                        if (x == hero.x || y == hero.y)
                            running = FALSE;
                        break;
                    case PASSAGE:
                        if (x == hero.x || y == hero.y)
                            passcount++;
                        break;
                    case FLOOR:

                        /*
                         * Stop by new passages in a
                         * maze (floor next to us)
                         */
                        if ((levtype == MAZELEV) &&
                                ((horizontal && x == hero.x && y != hero.y) ||
                                 (vertical &&   y == hero.y && x != hero.x)))
                            running = FALSE;

                    case '|':
                    case '-':
                    case ' ':
                        break;

                    default:
                        running = FALSE;
                        break;
                    }
                }
            }

    if (door_stop && !firstmove && passcount > 1)
        running = FALSE;

    /*
     * Do we have to light up the area (just stepped into a new
     * corridor)?
     */

    if (do_light && wakeup &&   /* wakeup will be true on a normal move */
            !(rp->r_flags & ISDARK) &&  /* We have some light */
            !ce(hero, player.t_oldpos)) /* Don't do anything if we didn't move */
        light(&hero);

    mvwaddch(cw, hero.y, hero.x, PLAYER);
    wmove(cw, oldy, oldx);

    if (wakeup)
    {
        player.t_oldpos = hero; /* Don't change if we didn't move */
        oldrp = rp;
    }
}
Esempio n. 2
0
/*
 * Attack the monster at the given location
 *
 * If no "weapon" is available, then "punch" the monster one time.
 *
 * We get blows until energy drops below that required for another blow, or
 * until the target monster dies. We use a wrapper to work out the number of
 * blows. We don't allow @ to spend more than 100 energy in one go, to avoid
 * slower monsters getting double moves.
 */
bool py_attack_real(int y, int x)
{
	int bonus, chance;

	monster_type *m_ptr = &mon_list[cave_m_idx[y][x]];
	monster_race *r_ptr = &r_info[m_ptr->r_idx];
	monster_lore *l_ptr = &l_list[m_ptr->r_idx];

	object_type *o_ptr;

	char m_name[80];

	bool fear = FALSE;

	bool do_quake = FALSE;
	bool dead = FALSE;

	u32b msg_type = 0;
	bool success = FALSE;
	
	const char *hit_verb = "ERROR";
	int dmg = 1;
	
	/* Default to punching for one damage */
	/* Maybe handle monster melee here -Simon */
	if(!rp_ptr->p_monster_index)
	{
		hit_verb = "punch";
		msg_type = MSG_HIT;
	}

	/*
	 * Hack -- if advanced innate attacks are disabled for this race, fall back
	 * on defaults <player>'s 1d1.
	 */
	 /* TODO: this -Simon */
	/* if (p_ptr->flags[NO_INNATE])
	{
			p_ptr = &r_info[0];
	} */


	/* Extract monster name (or "it") */
	monster_desc(m_name, sizeof(m_name), m_ptr, 0);

	/* Auto-Recall if possible and visible */
	if (m_ptr->ml) monster_race_track(m_ptr->r_idx);

	/* Track a new monster */
	if (m_ptr->ml) health_track(cave_m_idx[y][x]);

	/* Handle player fear (only for invisible monsters) */
	if (p_ptr->state.afraid)
	{
		message_format(MSG_AFRAID, 0,
				"You are too afraid to attack %s!",
				m_name);
		return (FALSE);
	}

	/* Disturb the monster */
	wake_monster(m_ptr);

	/* Get the weapon */
	o_ptr = &p_ptr->inventory[INVEN_WIELD];
	
		/* Calculate the "attack quality" */
	bonus = p_ptr->state.to_h + o_ptr->to_h;
	chance = (p_ptr->state.skills[SKILL_TO_HIT_MELEE] + (bonus * BTH_PLUS_ADJ));

	/* Handle innate melee -Simon */
	if(!o_ptr->k_idx && rp_ptr->p_monster_index)
	{
		for (int num = 0; (num < MONSTER_BLOW_MAX) && !dead; num++)
		{
			const slay_t *best_s_ptr = NULL;
			int type = GF_ARROW, type2 = 0, i;
			int flg = PROJECT_KILL | PROJECT_STOP | PROJECT_HIDE; // | PROJECT_PASS; TODO: figure out what this is and implement it -Simon
			char *p = "";
						
			if (!r_info[rp_ptr->p_monster_index].blow[num].method && !dead)
				continue;
					
			/* Test for hit */
			if (test_hit(chance, r_info[m_ptr->r_idx].ac, m_ptr->ml))
			{
				int mul = 1;
				int k = 0;
				
				/* Get the method */
				switch (r_info[rp_ptr->p_monster_index].blow[num].method)
				{
					case RBM_HIT:	p = "hit"; break;
					case RBM_TOUCH:	p = "touch"; break;
					case RBM_PUNCH:	p = "punch"; break;
					case RBM_KICK:	p = "kick"; break;
					case RBM_CLAW:	p = "claw"; break;
					case RBM_BITE:	p = "bite"; break;
					case RBM_STING:	p = "sting"; break;
					case RBM_BUTT:	p = "butt"; break;
					case RBM_CRUSH:	p = "crush"; break;
					case RBM_ENGULF:p = "engulf"; break;
					case RBM_PECK:	p = "peck"; break;
					case RBM_CRAWL:	p = "crawl on"; break;
					case RBM_DROOL:	p = "drool on"; break;
					case RBM_SPIT:	p = "spit on"; break;
					case RBM_SLIME:	p = "slime"; break;
					case RBM_GAZE:	p = "gaze at"; break;
					case RBM_WAIL:	p = "wail at"; break;
					case RBM_SPORE:	p = "release spores at"; break;
					case RBM_BEG:	p = "beg for money"; break;
					case RBM_INSULT:	p = "insult"; break;
					default: p = "attack";
				}

				/* Get the effect */
				switch (r_info[rp_ptr->p_monster_index].blow[num].effect)
				{
					case RBE_HURT: type = GF_ARROW; break;
					case RBE_DISEASE: type = GF_POIS; mul = 2; break;
					case RBE_POISON: type = GF_POIS; mul = 2; break;
					case RBE_LOSE_MANA: type = GF_DISENCHANT; break;
					case RBE_UN_BONUS: type = GF_DISENCHANT; mul = 2; break;
					case RBE_UN_POWER: type = GF_DISENCHANT; mul = 2; break; /* ? */
					case RBE_EAT_LIGHT: type = GF_DARK; mul = 2; break;
					case RBE_ACID: type = GF_ACID; mul = 2; break;
					case RBE_ELEC: type = GF_ELEC; mul = 2; break;
					case RBE_FIRE: type = GF_FIRE; mul = 2; break;
					case RBE_COLD: type = GF_COLD; mul = 2; break;
					case RBE_BLIND: type2 = GF_OLD_CONF; break; /* ? */
					case RBE_CONFUSE: type2 = GF_OLD_CONF; break;
					case RBE_TERRIFY: type2 = GF_TURN_ALL; break; /* ? */
					case RBE_PARALYZE: type2 = GF_OLD_SLEEP; break; /* ? */
					/* Earthquake would be natural, but all monsters
					 * with RBE_SHATTER are already humanoids
					 */
					case RBE_SHATTER: type = GF_ARROW; break;
					case RBE_EXP_10: type = GF_NETHER; mul = 2; break;
					case RBE_EXP_20: type = GF_NETHER; mul = 2; break;
					case RBE_EXP_40: type = GF_NETHER; mul = 2; break;
					case RBE_EXP_80: type = GF_NETHER; mul = 2; break;
					/* GF_CHAOS will polymorph, so it is bad */
					case RBE_HALLU: type = GF_DISENCHANT; mul = 2; break;
					default: type = GF_ARROW;
				}
			
				k = damroll(r_info[rp_ptr->p_monster_index].blow[num].d_dice, r_info[rp_ptr->p_monster_index].blow[num].d_side);
				/* Get the best attack from all slays or
				 * brands on all non-launcher equipment */
				for (i = INVEN_FINGER; i < INVEN_TOTAL; i++)
					improve_attack_modifier(&p_ptr->inventory[i], m_ptr, &best_s_ptr);
					
				if (best_s_ptr != NULL)
				{
					if (best_s_ptr->mult > mul)
					{
						p = best_s_ptr->melee_verb;
						mul = best_s_ptr->mult;
						if (best_s_ptr->resist_flag == RF_IM_ACID)
							type = GF_ACID;
						else if (best_s_ptr->resist_flag == RF_IM_ELEC)
							type = GF_ELEC;
						else if (best_s_ptr->resist_flag == RF_IM_FIRE)
							type = GF_FIRE;
						else if (best_s_ptr->resist_flag == RF_IM_COLD)
							type = GF_COLD;
						else if (best_s_ptr->resist_flag == RF_IM_POIS)
							type = GF_POIS;
					}
				}
				
				k *= mul;
				message_format(MSG_HIT, m_ptr->r_idx, "You %s %s.", p, m_name);
				/* Add to-dam bonus only if did some damage */
				if (k) k += p_ptr->state.to_d;
				if (k < 0) k = 0;
				
				/* Learn by use for other equipped items */
				wieldeds_notice_on_attack();
					
				/* If there is an extra effect, project it also, using 4*level as power */
				if (type2)
				{
					project(-1, 0, y, x, 4 * p_ptr->lev, type2, flg);
				}
							       
				/* Confusion attack */
				if (p_ptr->confusing)
				{
					/* Message */
					if (p_ptr->confusing)
						msg_print("Your limbs stop glowing.");
				
					/* Cancel glowing hands */
					p_ptr->confusing = FALSE;

					/* Confuse the monster */
					if (rf_has(r_ptr->flags, RF_NO_CONF))
					{
						if (m_ptr->ml)
						{
							rf_on(l_ptr->flags, RF_NO_CONF);
						}
						msg_format("%^s is unaffected.", m_name);
					}
					else if (randint0(100) < r_ptr->level)
					{
						msg_format("%^s appears slightly perplexed.", m_name);
					}
					else
					{
						msg_format("%^s appears confused.", m_name);
						m_ptr->confused += 10 + randint0(p_ptr->lev) / 5;
					}
				}
				
				/* Damage, check for fear and death */
				/* Makes elemental attacks do half their damage physically -Simon */
				if (type != GF_ARROW)
				{
					project(-1, 0, y, x, (k + 1)/2, type, flg);
					/* Make the physical portion TOP SECRET -Simon */
					flg &= ~(PROJECT_AWARE);
					project(-1, 0, y, x, k/2, GF_ARROW, flg);
				}
				else
					project(-1, 0, y, x, k, type, flg);
				/* Hack: check if the square is empty after we project the attack into it -Simon */
				dead = (cave_m_idx[y][x] == 0);
			
				/* Hack -- delay fear messages */
				if (fear && m_ptr->ml && !dead)
					message_format(MSG_FLEE, m_ptr->r_idx, "%^s flees in terror!", m_name);
			}
			/* Player misses */
			else
			{
				/* Message */
				message_format(MSG_MISS, m_ptr->r_idx, "You miss %s.", m_name);
			}
		}	
		return (TRUE);
	}
	
	else
	{
		/* See if the player hit */
		success = test_hit(chance, r_ptr->ac, m_ptr->ml);

		/* If a miss, skip this hit */
		if (!success)
		{
			message_format(MSG_MISS, m_ptr->r_idx, "You miss %s.", m_name);
			return (FALSE);
		}

		/* Handle normal weapon */
		if (o_ptr->k_idx)
		{
			int i;
			const slay_t *best_s_ptr = NULL;

			hit_verb = "hit";

			/* Get the best attack from all slays or
			 * brands on all non-launcher equipment */
			for (i = INVEN_FINGER; i < INVEN_TOTAL; i++)
				improve_attack_modifier(&p_ptr->inventory[i], m_ptr,
				&best_s_ptr);

			improve_attack_modifier(o_ptr, m_ptr, &best_s_ptr);
			if (best_s_ptr != NULL)
				hit_verb = best_s_ptr->melee_verb;

			dmg = damroll(o_ptr->dd, o_ptr->ds);
			dmg *= (best_s_ptr == NULL) ? 1 : best_s_ptr->mult;

			if (p_ptr->state.impact && (dmg > 50))
				do_quake = TRUE;

			dmg += o_ptr->to_d;
			dmg = critical_norm(o_ptr->weight, o_ptr->to_h, dmg, &msg_type);

			/* Learn by use for the weapon */
			object_notice_attack_plusses(o_ptr);

			if (do_quake)
				wieldeds_notice_flag(OF_IMPACT);
		}

		/* Learn by use for other equipped items */
		wieldeds_notice_on_attack();

		/* Apply the player damage bonuses */
		dmg += p_ptr->state.to_d;

		/* No negative damage */
		if (dmg <= 0) dmg = 0;

		/* Tell the player what happened */
		if (dmg <= 0)
			message_format(MSG_MISS, m_ptr->r_idx,
						   "You fail to harm %s.", m_name);
		else if (msg_type == MSG_HIT)
			message_format(MSG_HIT, m_ptr->r_idx, "You %s %s.",
						   hit_verb, m_name);
		else if (msg_type == MSG_HIT_GOOD)
			message_format(MSG_HIT_GOOD, m_ptr->r_idx, "You %s %s. %s",
						   hit_verb, m_name, "It was a good hit!");
		else if (msg_type == MSG_HIT_GREAT)
			message_format(MSG_HIT_GREAT, m_ptr->r_idx, "You %s %s. %s",
						   hit_verb, m_name, "It was a great hit!");
		else if (msg_type == MSG_HIT_SUPERB)
			message_format(MSG_HIT_SUPERB, m_ptr->r_idx, "You %s %s. %s",
						   hit_verb, m_name, "It was a superb hit!");
		else if (msg_type == MSG_HIT_HI_GREAT)
			message_format(MSG_HIT_HI_GREAT, m_ptr->r_idx, "You %s %s. %s",
						   hit_verb, m_name, "It was a *GREAT* hit!");
		else if (msg_type == MSG_HIT_HI_SUPERB)
			message_format(MSG_HIT_HI_SUPERB, m_ptr->r_idx, "You %s %s. %s",
						   hit_verb, m_name, "It was a *SUPERB* hit!");

		/* Complex message */
		if (p_ptr->wizard)
			msg_format("You do %d (out of %d) damage.", dmg, m_ptr->hp);

		/* Confusion attack */
		if (p_ptr->confusing)
		{
			/* Cancel glowing hands */
			p_ptr->confusing = FALSE;

			/* Message */
			msg_print("Your limbs stop glowing.");

			/* Update the lore */
			if (m_ptr->ml)
				rf_on(l_ptr->flags, RF_NO_CONF);

			/* Confuse the monster */
			if (rf_has(r_ptr->flags, RF_NO_CONF))
				msg_format("%^s is unaffected.", m_name);
			else if (randint0(100) < r_ptr->level)
				msg_format("%^s is unaffected.", m_name);
			else
			{
				msg_format("%^s appears confused.", m_name);
				m_ptr->confused += 10 + randint0(p_ptr->lev) / 5;
			}
		}

		/* Damage, check for fear and death */
		dead = mon_take_hit(cave_m_idx[y][x], dmg, &fear, NULL);

		/* Hack -- delay fear messages */
		if (fear && m_ptr->ml)
			message_format(MSG_FLEE, m_ptr->r_idx, "%^s flees in terror!",
			m_name);

		/* Mega-Hack -- apply earthquake brand */
		if (do_quake) earthquake(p_ptr->py, p_ptr->px, 10);

		return (dead);
	}
}