view arogue5/fight.c @ 158:2515e03b2f09

arogue7, xrogue: add 'install' targets to Makefiles. 'make install' and 'make uninstall' should now work as expected.
author John "Elwin" Edwards
date Thu, 04 Jun 2015 17:08:40 -0400
parents 0ed67132cf10
children 56e748983fa8
line wrap: on
line source

/*
 * All the fighting gets done here
 *
 * Advanced Rogue
 * Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T
 * All rights reserved.
 *
 * Based on "Rogue: Exploring the Dungeons of Doom"
 * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
 * All rights reserved.
 *
 * See the file LICENSE.TXT for full copyright and licensing information.
 */

#include "curses.h"
#include <ctype.h>
#include <string.h>
#include "rogue.h"

#define CONF_DAMAGE	-1
#define PARAL_DAMAGE	-2
#define DEST_DAMAGE	-3

static const struct matrix att_mat[5] = {
/* Base		Max_lvl,	Factor,		Offset,		Range */
{  10,		25,		2,		1,		2 },
{  9,		18,		2,		1,		5 },
{  10,		19,		2,		1,		3 },
{  10,		21,		2,		1,		4 },
{   7,		25,		1,		0,		2 }
};

/*
 * fight:
 *	The player attacks the monster.
 */

fight(mp, weap, thrown)
register coord *mp;
struct object *weap;
bool thrown;
{
    register struct thing *tp;
    register struct linked_list *item;
    register bool did_hit = TRUE;
    bool back_stab = FALSE;

    /*
     * Find the monster we want to fight
     */
    if ((item = find_mons(mp->y, mp->x)) == NULL) {
	return(FALSE); /* must have killed him already */
    }
    tp = THINGPTR(item);
    /*
     * Since we are fighting, things are not quiet so no healing takes
     * place.
     */
    player.t_quiet = 0;
    tp->t_quiet = 0;

    /*
     * if its in the wall, we can't hit it
     */
    if (on(*tp, ISINWALL) && off(player, CANINWALL))
	return(FALSE);

    /*
     * Let him know it was really a mimic (if it was one).
     */
    if (on(*tp, ISDISGUISE) && (tp->t_type != tp->t_disguise) &&
	off(player, ISBLIND))
    {
	msg("Wait! That's a %s!", monsters[tp->t_index].m_name);
	turn_off(*tp, ISDISGUISE);
	did_hit = thrown;
    }
    if (on(*tp, CANSURPRISE) && off(player, ISBLIND) && !ISWEARING(R_ALERT)) {
	msg("Wait! There's a %s!", monsters[tp->t_index].m_name);
	turn_off(*tp, CANSURPRISE);
	did_hit = thrown;
    }
    /*
     * if he's a thief and the creature is asleep then he gets a chance
     * for a backstab
     */
    if (player.t_ctype == C_THIEF			 	 && 
	(!on(*tp, ISRUN) || on(*tp, ISHELD) || tp->t_no_move > 0)&&
	!on(*tp, NOSTAB))
	back_stab = TRUE;

    runto(tp, &hero);

    if (did_hit)
    {
	register const char *mname;

	did_hit = FALSE;
	mname = (on(player, ISBLIND)) ? "it" : monsters[tp->t_index].m_name;
	if (!can_blink(tp) &&
	    ( ((weap != NULL) && (weap->o_type == RELIC)) ||
	     ((off(*tp, MAGICHIT)  || ((weap != NULL) && (weap->o_hplus > 0 || weap->o_dplus > 0)) ) &&
	      (off(*tp, BMAGICHIT) || ((weap != NULL) && (weap->o_hplus > 1 || weap->o_dplus > 1)) ) &&
	      (off(*tp, CMAGICHIT) || ((weap != NULL) && (weap->o_hplus > 2 || weap->o_dplus > 2)) ) ) )
	    && roll_em(&player, tp, weap, thrown, cur_weapon, back_stab))
	{
	    did_hit = TRUE;

	    if (on(*tp, NOMETAL) && weap != NULL &&
		weap->o_type != RELIC && weap->o_flags & ISMETAL) {
		sprintf(outstring,"Your %s passes right through the %s!",
		    weaps[weap->o_which].w_name, mname);
		msg(outstring);
	    }
	    else if (thrown) {
		tp->t_wasshot = TRUE;
		thunk(weap, tp, mname);
	    }
	    else
		hit(weap, tp, NULL, mname, back_stab);

	    /* If the player hit a rust monster, he better have a + weapon */
	    if (on(*tp, CANRUST) && !thrown && (weap != NULL) &&
		weap->o_type != RELIC &&
		(weap->o_flags & ISMETAL) &&
		!(weap->o_flags & ISPROT) &&
		(weap->o_hplus < 1) && (weap->o_dplus < 1)) {
		if (rnd(100) < 50) weap->o_hplus--;
		else weap->o_dplus--;
		msg(terse ? "Your %s weakens!"
			  : "Your %s appears to be weaker now!",
		    weaps[weap->o_which].w_name);
	    }
		
	    /* If the player hit something that shrieks, wake the dungeon */
	    if (on(*tp, CANSHRIEK)) {
		turn_off(*tp, CANSHRIEK);
		msg("The %s emits a piercing shriek.", mname);
		aggravate();
	    }

	    /* If the player hit something that can surprise, it can't now */
	    if (on(*tp, CANSURPRISE)) turn_off(*tp, CANSURPRISE);


	    /* 
	     * Can the player confuse? 
	     */
	    if (on(player, CANHUH) && !thrown) {
		msg("Your hands stop glowing red");
		msg("The %s appears confused.", mname);
		turn_on(*tp, ISHUH);
		turn_off(player, CANHUH);
	    }
	    /*
	     * does the creature explode when hit?
	     */
	    if (on(*tp, CANEXPLODE))
		explode(tp);

	    /* 
	     * Merchants just disappear if hit 
	     */
	    if (on(*tp, CANSELL)) {
		msg("The %s disappears with his wares in a flash.",mname);
		killed(item, FALSE, FALSE);
	    }

	    else if (tp->t_stats.s_hpt <= 0)
		killed(item, TRUE, TRUE);

	    /* If the monster is fairly intelligent and about to die, it
	     * may turn tail and run.
	     */
	    else if ((tp->t_stats.s_hpt < max(10, tp->maxstats.s_hpt/10)) &&
		     (rnd(25) < tp->t_stats.s_intel)) {
		turn_on(*tp, ISFLEE);

		/* If monster was suffocating, stop it */
		if (on(*tp, DIDSUFFOCATE)) {
		    turn_off(*tp, DIDSUFFOCATE);
		    extinguish(suffocate);
		}

		/* If monster held us, stop it */
		if (on(*tp, DIDHOLD) && (--hold_count == 0))
			turn_off(player, ISHELD);
		turn_off(*tp, DIDHOLD);
	    }
	}
	else {
	    if (thrown)
		bounce(weap, tp, mname);
	    else
		miss(weap, tp, NULL, mname);
	}
    }
    count = 0;
    return did_hit;
}

/*
 * attack:
 *	The monster attacks the player
 */

attack(mp, weapon, thrown)
register struct thing *mp;
register struct object *weapon;
bool thrown;
{
    register const char *mname;
    register bool did_hit = FALSE;
    register struct object *wielded;	/* The wielded weapon */

    /*
     * Since this is an attack, stop running and any healing that was
     * going on at the time.
     */
    running = FALSE;
    player.t_quiet = 0;
    mp->t_quiet = 0;

    if (on(*mp, ISDISGUISE) && off(player, ISBLIND))
	turn_off(*mp, ISDISGUISE);
    mname = on(player, ISBLIND) ? "it" : monsters[mp->t_index].m_name;

    /*
     * Try to find a weapon to wield.  Wield_weap will return a
     * projector if weapon is a projectile (eg. bow for arrow).
     * If weapon is NULL, it will try to find a suitable weapon.
     */
    wielded = wield_weap(weapon, mp);
    if (weapon == NULL) weapon = wielded;

    if (roll_em(mp, &player, weapon, thrown, wielded, FALSE)) {
	did_hit = TRUE;

	if (thrown) m_thunk(weapon, mp, mname);
	else hit(weapon, mp, mname, NULL, FALSE);

	if (pstats.s_hpt <= 0)
	    death(mp->t_index);	/* Bye bye life ... */

	/*
	 * suprising monsters appear after they shoot at you 
	 */
	if (thrown) {
	    if (on(*mp, CANSURPRISE)) 
		turn_off(*mp, CANSURPRISE);
	}
	if (!thrown) {
	    /*
	     * If a vampire hits, it may take half your hit points
	     */
	    if (on(*mp, CANSUCK) && !save(VS_MAGIC, &player, 0)) {
		if (pstats.s_hpt == 1) death(mp->t_index);
		else {
		  pstats.s_hpt /= 2;
		  msg("You feel your life force being drawn from you.");
		}
	    }

	    /*
	     * Stinking monsters make player weaker (to hit)
	     */
	    if (on(*mp, CANSTINK)) {
		turn_off(*mp, CANSTINK);
		if (!save(VS_POISON, &player, 0)) {
		    msg("The stench of the %s sickens you.", mname);
		    if (on(player, HASSTINK)) lengthen(unstink, STINKTIME);
		    else {
			turn_on(player, HASSTINK);
			fuse(unstink, 0, STINKTIME, AFTER);
		    }
		}
	    }

	    /*
	     * Chilling monster reduces strength each time
	     */
	    if (on(*mp, CANCHILL)) {
		if (!ISWEARING(R_SUSABILITY) && !save(VS_POISON, &player, 0)) {
		    msg("You cringe at the %s's chilling touch.", mname);
		    chg_str(-1);
		    if (lost_str++ == 0)
			fuse(res_strength, 0, CHILLTIME, AFTER);
		    else lengthen(res_strength, CHILLTIME);
		}
	    }

	    /*
	     * itching monsters reduce dexterity (temporarily)
	     */
	    if (on(*mp, CANITCH) && !save(VS_POISON, &player, 0)) {
		msg("The claws of the %s scratch you", mname);
		if(ISWEARING(R_SUSABILITY)) {
		    msg("The scratch has no effect");
		}
		else {
		    turn_on(player, HASITCH);
		    add_dexterity(TRUE);
		    lost_dext++;
		    fuse(un_itch, 0, roll(HEALTIME,SICKTIME), AFTER);
		}
	    }


	    /*
	     * If a hugging monster hits, it may SQUEEEEEEEZE
	     */
	    if (on(*mp, CANHUG)) {
		if (roll(1,20) >= 18 || roll(1,20) >= 18) {
		    msg("The %s squeezes you against itself.", mname);
		    if ((pstats.s_hpt -= roll(2,8)) <= 0)
			death(mp->t_index);
		}
	    }

	    /*
	     * If a disease-carrying monster hits, there is a chance the
	     * player will catch the disease
	     */
	    if (on(*mp, CANDISEASE) &&
		(rnd(pstats.s_const) < mp->t_stats.s_lvl) &&
		off(player, HASDISEASE)) {
		if (ISWEARING(R_HEALTH)) msg("The wound heals quickly.");
		else {
		    turn_on(player, HASDISEASE);
		    fuse(cure_disease, 0, roll(HEALTIME,SICKTIME), AFTER);
		    msg(terse ? "You have been diseased."
			: "You have contracted a disease!");
		}
	    }

	    /*
	     * If a rust monster hits, you lose armor
	     */
	    if (on(*mp, CANRUST)) { 
		if (cur_armor != NULL				&&
		    cur_armor->o_which != LEATHER		&&
		    cur_armor->o_which != STUDDED_LEATHER	&&
		    cur_armor->o_which != PADDED_ARMOR		&&
		    !(cur_armor->o_flags & ISPROT)		&&
		    cur_armor->o_ac < pstats.s_arm+1		) {
			msg(terse ? "Your armor weakens"
			    : "Your armor appears to be weaker now. Oh my!");
			cur_armor->o_ac++;
	        }
		if (cur_misc[WEAR_BRACERS] != NULL		&&
		    cur_misc[WEAR_BRACERS]->o_ac > 0		&&
		    !(cur_misc[WEAR_BRACERS]->o_flags & ISPROT)) {
			cur_misc[WEAR_BRACERS]->o_ac--;
			if (cur_misc[WEAR_BRACERS]->o_ac == 0) {
			    register struct linked_list *item;

			    for (item=pack; item!=NULL; item=next(item)) {
				if (OBJPTR(item) == cur_misc[WEAR_BRACERS]) {
				    detach(pack, item);
				    o_discard(item);
				    break;
				}
			    }
			    msg ("Your bracers crumble and fall off!");
			    cur_misc[WEAR_BRACERS] = NULL;
			    inpack--;
			}
			else {
			    msg("Your bracers weaken!");
			}
		}
	    }
	    /*
	     * If can dissolve and hero has leather type armor
	     */
	    if (on(*mp, CANDISSOLVE) && cur_armor != NULL &&
		(cur_armor->o_which == LEATHER		  ||
		 cur_armor->o_which == STUDDED_LEATHER	  ||
		 cur_armor->o_which == PADDED_ARMOR)	  &&
		!(cur_armor->o_flags & ISPROT) &&
		cur_armor->o_ac < pstats.s_arm+1) {
		msg(terse ? "Your armor dissolves"
		    : "Your armor appears to dissolve. Oh my!");
		cur_armor->o_ac++;
	    }

	    /* If a surprising monster hit you, you can see it now */
	    if (on(*mp, CANSURPRISE)) turn_off(*mp, CANSURPRISE);

	    /*
	     * If an infesting monster hits you, you get a parasite or rot
	     */
	    if (on(*mp, CANINFEST) && rnd(pstats.s_const) < mp->t_stats.s_lvl) {
		if (ISWEARING(R_HEALTH)) msg("The wound quickly heals.");