diff srogue/fight.c @ 36:2128c7dc8a40

Import Super-Rogue 9.0 from the Roguelike Restoration Project (r1490)
author elwin
date Thu, 25 Nov 2010 12:21:41 +0000
parents
children 94a0d9dd5ce1
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/srogue/fight.c	Thu Nov 25 12:21:41 2010 +0000
@@ -0,0 +1,711 @@
+/*
+ * All the fighting gets done here
+ *
+ * @(#)fight.c	9.0	(rdk)	 7/17/84
+ *
+ * Super-Rogue
+ * Copyright (C) 1984 Robert D. Kindelberger
+ * 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 <ctype.h>
+#include "rogue.h"
+#include "rogue.ext"
+
+
+/*
+ * fight:
+ *	The player attacks the monster.
+ */
+fight(mp, weap, thrown)
+struct coord *mp;
+struct object *weap;
+bool thrown;
+{
+
+	reg struct thing *tp;
+	reg struct stats *st;
+	reg struct linked_list *item;
+	bool did_hit = TRUE;
+
+	if (pl_on(ISETHER))			/* cant fight when ethereal */
+		return 0;
+
+	if ((item = find_mons(mp->y, mp->x)) == NULL) {
+		mvaddch(mp->y, mp->x, FLOOR);
+		mvwaddch(mw, mp->y, mp->x, ' ');
+		look(FALSE);
+		msg("That monster must have been an illusion.");
+		return 0;
+	}
+	tp = THINGPTR(item);
+	st = &tp->t_stats;
+	/*
+	 * Since we are fighting, things are not quiet so
+	 * no healing takes place.
+	 */
+	quiet = 0;
+	isfight = TRUE;
+	runto(mp, &hero);
+	/*
+	 * Let him know it was really a mimic (if it was one).
+	 */
+	if(tp->t_type == 'M' && tp->t_disguise != 'M' && pl_off(ISBLIND)) {
+		msg("Wait! That's a mimic!");
+		tp->t_disguise = 'M';
+		did_hit = thrown;
+	}
+	if (did_hit) {
+		reg char *mname;
+
+		did_hit = FALSE;
+		if (pl_on(ISBLIND))
+			mname = "it";
+		else
+			mname = monsters[tp->t_indx].m_name;
+		/*
+		 * If the hero can see the invisibles, then
+		 * make it easier to hit.
+		 */
+		if (pl_on(CANSEE) && on(*tp, ISINVIS) && off(*tp, WASHIT)) {
+			tp->t_flags |= WASHIT;
+			st->s_arm += 3;
+		}
+		if (roll_em(him, st, weap, thrown)) {
+			did_hit = TRUE;
+			if (thrown)
+				thunk(weap, mname);
+			else
+				hit(NULL);
+			if (pl_on(CANHUH)) {
+				msg("Your hands stop glowing red");
+				msg("The %s appears confused.", mname);
+				tp->t_flags |= ISHUH;
+				player.t_flags &= ~CANHUH;
+				/*
+				 * If our hero was stuck by a bone devil,
+				 * release him now because the devil is
+				 * confused.
+				 */
+				if (pl_on(ISHELD))
+					unhold(tp->t_type);
+			}
+			if (st->s_hpt <= 0)
+				killed(item, TRUE);
+			else if (monhurt(tp) && off(*tp, ISWOUND)) {
+				if (levtype != MAZELEV && tp->t_room != NULL &&
+				  !rf_on(tp->t_room, ISTREAS)) {
+					tp->t_flags |= ISWOUND;
+					msg("You wounded %s.",prname(mname,FALSE));
+					unhold(tp->t_type);
+				}
+			}
+		}
+		else {
+			if (thrown)
+				bounce(weap, mname);
+			else
+				miss(NULL);
+		}
+	}
+	count = 0;
+	return did_hit;
+}
+
+
+/*
+ * attack:
+ *	The monster attacks the player
+ */
+attack(mp)
+struct thing *mp;
+{
+	reg char *mname;
+
+	if (pl_on(ISETHER))		/* ethereal players cant be hit */
+		return(0);
+	if (mp->t_flags & ISPARA)	/* paralyzed monsters */
+		return(0);
+	running = FALSE;
+	quiet = 0;
+	isfight = TRUE;
+	if (mp->t_type == 'M' && pl_off(ISBLIND))
+		mp->t_disguise = 'M';
+	if (pl_on(ISBLIND))
+		mname = "it";
+	else
+		mname = monsters[mp->t_indx].m_name;
+	if (roll_em(&mp->t_stats, him, NULL, FALSE)) {
+		if (pl_on(ISINVINC)) {
+			msg("%s does not harm you.",prname(mname,TRUE));
+		}
+		else {
+			nochange = FALSE;
+			if (mp->t_type != 'E')
+				hit(mname);
+			if (him->s_hpt <= 0)
+				death(mp->t_indx);
+			if (off(*mp, ISCANC))
+				switch (mp->t_type) {
+				case 'R':
+					if (hurt_armor(cur_armor)) {
+						msg("Your armor weakens.");
+						cur_armor->o_ac++;
+					}
+				when 'E':
+				/*
+				 * The gaze of the floating eye hypnotizes you
+				 */
+					if (pl_off(ISBLIND) && player.t_nocmd <= 0) {
+						player.t_nocmd = rnd(16) + 25;
+						msg("You are transfixed.");
+					}
+				when 'Q':
+					if (!save(VS_POISON) && !iswearing(R_SUSAB)) {
+						if (him->s_ef.a_dex > MINABIL) {
+							chg_abil(DEX, -1, TRUE);
+							msg("You feel less agile.");
+						}
+					}
+				when 'A':
+					if (!save(VS_POISON) && herostr() > MINABIL) {
+						if (!iswearing(R_SUSTSTR) && !iswearing(R_SUSAB)) {
+							if (levcount > 0) {
+								chg_abil(STR, -1, TRUE);
+								msg("A sting has weakened you");
+							}
+						}
+						else
+							msg("Sting has no effect.");
+					}
+				when 'W':
+					if (rnd(100) < 15 && !iswearing(R_SUSAB)) {
+						if (him->s_exp <= 0)
+							death(mp->t_indx);
+						msg("You suddenly feel weaker.");
+						if (--him->s_lvl == 0) {
+							him->s_exp = 0;
+							him->s_lvl = 1;
+						}
+						else
+							him->s_exp = e_levels[him->s_lvl - 1] + 1;
+						chg_hpt(-roll(1,10),TRUE,mp->t_indx);
+					}
+				when 'F':
+					player.t_flags |= ISHELD;
+					sprintf(monsters[midx('F')].m_stats.s_dmg,"%dd1",++fung_hit);
+				when 'L': {
+					long lastpurse;
+					struct linked_list *lep;
+
+					lastpurse = purse;
+					purse -= GOLDCALC;
+					if (!save(VS_MAGIC))
+						purse -= GOLDCALC + GOLDCALC + GOLDCALC + GOLDCALC;
+					if (purse < 0)
+						purse = 0;
+					if (purse != lastpurse)
+						msg("Your purse feels lighter.");
+					lep = find_mons(mp->t_pos.y,mp->t_pos.x);
+					if (lep != NULL)
+					{
+						remove_monster(&mp->t_pos, lep);
+						mp = NULL;
+					}
+				}
+				when 'N': {
+					struct linked_list *steal, *list;
+					struct object *sobj;
+					int stworth = 0, wo;
+
+					/*
+					 * Nymph's steal a magic item, look through the pack
+					 * and pick out one we like, namely the object worth
+					 * the most bucks.
+					 */
+					steal = NULL;
+					for (list = pack; list != NULL; list = next(list)) {
+						wo = get_worth(OBJPTR(list));
+						if (wo > stworth) {
+							stworth = wo;
+							steal = list;
+						}
+					}
+					if (steal != NULL) {
+						sobj = OBJPTR(steal);
+						if (o_off(sobj, ISPROT)) {
+							struct linked_list *nym;
+
+							nym = find_mons(mp->t_pos.y, mp->t_pos.x);
+							if (nym != NULL)
+							{
+								remove_monster(&mp->t_pos, nym);
+								mp = NULL;
+							}
+							msg("She stole %s!", inv_name(sobj, TRUE));
+							detach(pack, steal);
+							discard(steal);
+							cur_null(sobj);
+							updpack();
+						}
+					}
+				}
+				when 'c':
+					if (!save(VS_PETRIFICATION)) {
+						msg("Your body begins to solidify.");
+						msg("You are turned to stone !!! --More--");
+						wait_for(cw, ' ');
+						death(mp->t_indx);
+					}
+				when 'd':
+					if (rnd(100) < 50 && !(mp->t_flags & ISHUH))
+						player.t_flags |= ISHELD;
+					if (!save(VS_POISON)) {
+						if (iswearing(R_SUSAB) || iswearing(R_SUSTSTR))
+							msg("Sting has no effect.");
+						else {
+							int fewer, ostr;
+
+							fewer = roll(1,4);
+							ostr = herostr();
+							chg_abil(STR,-fewer,TRUE);
+							if (herostr() < ostr) {
+								fewer = ostr - herostr();
+								fuse(rchg_str, fewer - 1, 10);
+							}
+							msg("You feel weaker now.");
+						}
+					}
+				when 'g':
+					if (!save(VS_BREATH) && !iswearing(R_BREATH)) {
+						msg("You feel singed.");
+						chg_hpt(-roll(1,8),FALSE,mp->t_indx);
+					}
+				when 'h':
+					if (!save(VS_BREATH) && !iswearing(R_BREATH)) {
+						msg("You are seared.");
+						chg_hpt(-roll(1,4),FALSE,mp->t_indx);
+					}
+				when 'p':
+					if (!save(VS_POISON) && herostr() > MINABIL) {
+						if (!iswearing(R_SUSTSTR) && !iswearing(R_SUSAB)) {
+							msg("You are gnawed.");
+							chg_abil(STR,-1,TRUE);
+						}
+					}
+				when 'u':
+					if (!save(VS_POISON) && herostr() > MINABIL) {
+						if (!iswearing(R_SUSTSTR) && !iswearing(R_SUSAB)) {
+							msg("You are bitten.");
+							chg_abil(STR, -1, TRUE);
+							fuse(rchg_str, 1, roll(5,10));
+				 		}
+					}
+				when 'w':
+					if (!save(VS_POISON) && !iswearing(R_SUSAB)) {
+						msg("You feel devitalized.");
+						chg_hpt(-1,TRUE,mp->t_indx);
+					}
+				when 'i':
+					if (!save(VS_PARALYZATION) && !iswearing(R_SUSAB)) {
+						if (pl_on(ISSLOW))
+							lengthen(notslow,roll(3,10));
+						else {
+							msg("You feel impaired.");
+							player.t_flags |= ISSLOW;
+							fuse(notslow,TRUE,roll(5,10));
+						}
+					}
+				otherwise:
+					break;
+			}
+		}
+	}
+	else if (mp->t_type != 'E') {
+		if (mp->t_type == 'F') {
+			him->s_hpt -= fung_hit;
+			if (him->s_hpt <= 0)
+				death(mp->t_indx);
+		}
+		miss(mname);
+	}
+	flushinp();					/* flush type ahead */
+	count = 0;
+
+	if (mp == NULL)
+		return(-1);
+	else
+		return(0);
+}
+
+
+/*
+ * swing:
+ *	Returns true if the swing hits
+ */
+swing(at_lvl, op_arm, wplus)
+int at_lvl, op_arm, wplus;
+{
+	reg int res = rnd(20)+1;
+	reg int need = (21 - at_lvl) - op_arm;
+
+	return (res + wplus >= need);
+}
+
+
+/*
+ * check_level:
+ *	Check to see if the guy has gone up a level.
+ */
+check_level()
+{
+	reg int lev, add, dif;
+
+	for (lev = 0; e_levels[lev] != 0; lev++)
+	if (e_levels[lev] > him->s_exp)
+		break;
+	lev += 1;
+	if (lev > him->s_lvl) {
+		dif = lev - him->s_lvl;
+		add = roll(dif, 10) + (dif * getpcon(him));
+		him->s_maxhp += add;
+		if ((him->s_hpt += add) > him->s_maxhp)
+			him->s_hpt = him->s_maxhp;
+		msg("Welcome to level %d", lev);
+	}
+	him->s_lvl = lev;
+}
+
+
+/*
+ * roll_em:
+ *	Roll several attacks
+ */
+roll_em(att, def, weap, hurl)
+struct stats *att, *def;
+struct object *weap;
+bool hurl;
+{
+	reg char *cp;
+	reg int ndice, nsides, def_arm, prop_hplus, prop_dplus;
+	reg bool did_hit = FALSE;
+	char *mindex();
+
+	prop_hplus = prop_dplus = 0;
+	if (weap == NULL) {
+		cp = att->s_dmg;
+	}
+	else if (hurl) {
+		if (o_on(weap,ISMISL) && cur_weapon != NULL &&
+		  cur_weapon->o_which == weap->o_launch) {
+			cp = weap->o_hurldmg;
+			prop_hplus = cur_weapon->o_hplus;
+			prop_dplus = cur_weapon->o_dplus;
+		}
+		else
+			cp = (o_on(weap,ISMISL) ? weap->o_damage : weap->o_hurldmg);
+	}
+	else {
+		cp = weap->o_damage;
+		/*
+		 * Drain a staff of striking
+		 */
+		if (weap->o_type == STICK && weap->o_which == WS_HIT
+		  && weap->o_charges == 0) {
+			strcpy(weap->o_damage, "0d0");
+			weap->o_hplus = weap->o_dplus = 0;
+		}
+    }
+	while(1) {
+		int damage;
+		int hplus = prop_hplus + (weap == NULL ? 0 : weap->o_hplus);
+		int dplus = prop_dplus + (weap == NULL ? 0 : weap->o_dplus);
+
+		if (att == him && weap == cur_weapon) {
+			if (isring(LEFT, R_ADDDAM))
+				dplus += cur_ring[LEFT]->o_ac;
+			else if (isring(LEFT, R_ADDHIT))
+				hplus += cur_ring[LEFT]->o_ac;
+			if (isring(RIGHT, R_ADDDAM))
+				dplus += cur_ring[RIGHT]->o_ac;
+			else if (isring(RIGHT, R_ADDHIT))
+				hplus += cur_ring[RIGHT]->o_ac;
+		}
+		ndice = atoi(cp);
+		if ((cp = mindex(cp, 'd')) == NULL)
+			break;
+		nsides = atoi(++cp);
+
+		if (def == him) {			/* defender is hero */
+			if (cur_armor != NULL)
+				def_arm = cur_armor->o_ac;
+			else
+				def_arm = def->s_arm;
+			if (isring(LEFT, R_PROTECT))
+				def_arm -= cur_ring[LEFT]->o_ac;
+			if (isring(RIGHT, R_PROTECT))
+				def_arm -= cur_ring[RIGHT]->o_ac;
+		}
+		else						/* defender is monster */
+			def_arm = def->s_arm;
+		if (hurl)
+			hplus += getpdex(att,TRUE);
+		if (swing(att->s_lvl, def_arm + getpdex(def, FALSE),
+		  hplus + str_plus(att))) {
+			reg int proll;
+
+			proll = roll(ndice, nsides);
+			damage = dplus + proll + add_dam(att);
+			if (pl_off(ISINVINC) || def != him)
+				def->s_hpt -= max(0, damage);
+			did_hit = TRUE;
+		}
+		if ((cp = mindex(cp, '/')) == NULL)
+			break;
+		cp++;
+	}
+	return did_hit;
+}
+
+
+/*
+ * mindex:
+ *	Look for char 'c' in string pointed to by 'cp'
+ */
+char *
+mindex(cp, c)
+char *cp, c;
+{
+	reg int i;
+
+	for (i = 0; i < 3; i++)
+		if (*cp != c)  cp++;
+	if (*cp == c)
+		return cp;
+	else
+		return NULL;
+}
+
+
+/*
+ * prname:
+ *	The print name of a combatant
+ */
+char *
+prname(who, upper)
+char *who;
+bool upper;
+{
+static char tbuf[LINLEN];
+
+	*tbuf = '\0';
+	if (who == 0)
+		strcpy(tbuf, "you"); 
+	else if (pl_on(ISBLIND))
+		strcpy(tbuf, "it");
+	else {
+		strcpy(tbuf, "the ");
+		strcat(tbuf, who);
+	}
+	if (upper)
+		*tbuf = toupper(*tbuf);
+	return tbuf;
+}
+
+/*
+ * hit:
+ *	Print a message to indicate a succesful hit
+ */
+hit(er)
+char *er;
+{
+	msg("%s hit.",prname(er, TRUE));
+}
+
+
+/*
+ * miss:
+ *	Print a message to indicate a poor swing
+ */
+miss(er)
+char *er;
+{
+	msg("%s miss%s.",prname(er, TRUE),(er == 0 ? "":"es"));
+}
+
+
+/*
+ * save_throw:
+ *	See if a creature saves against something
+ */
+save_throw(which, tp)
+int which;
+struct thing *tp;
+{
+	reg int need;
+	reg struct stats *st;
+
+	st = &tp->t_stats;
+	need = 14 + which - (st->s_lvl / 2) - getpwis(st);
+	return (roll(1, 20) >= need);
+}
+
+
+/*
+ * save:
+ *	See if he saves against various nasty things
+ */
+save(which)
+int which;
+{
+	return save_throw(which, &player);
+}
+
+/*
+ * raise_level:
+ *	The guy just magically went up a level.
+ */
+raise_level()
+{
+	him->s_exp = e_levels[him->s_lvl-1] + 1L;
+	check_level();
+}
+
+
+/*
+ * thunk:
+ *	A missile hits a monster
+ */
+thunk(weap, mname)
+struct object *weap;
+char *mname;
+{
+	if (weap->o_type == WEAPON)
+		msg("The %s hits the %s.",w_magic[weap->o_which].mi_name,mname);
+	else
+		msg("You hit the %s.", mname);
+}
+
+
+/*
+ * bounce:
+ *	A missile misses a monster
+ */
+bounce(weap, mname)
+struct object *weap;
+char *mname;
+{
+	if (weap->o_type == WEAPON)
+		msg("The %s misses the %s.", w_magic[weap->o_which].mi_name,mname);
+	else
+		msg("You missed the %s.", mname);
+}
+
+
+/*
+ * remove:
+ *	Remove a monster from the screen
+ */
+remove_monster(mp, item)
+struct coord *mp;
+struct linked_list *item;
+{
+	reg char what;
+
+	mvwaddch(mw, mp->y, mp->x, ' ');
+	if (pl_on(ISBLIND))
+		what = ' ';							/* if blind, then a blank */
+	else
+		what = (THINGPTR(item))->t_oldch;	/* normal char */
+	mvwaddch(cw, mp->y, mp->x, what);
+	detach(mlist, item);
+	discard(item);
+}
+
+
+/*
+ * is_magic:
+ *	Returns true if an object radiates magic
+ */
+is_magic(obj)
+struct object *obj;
+{
+	switch (obj->o_type) {
+		case ARMOR:
+			return obj->o_ac != armors[obj->o_which].a_class;
+		case WEAPON:
+			return obj->o_hplus != 0 || obj->o_dplus != 0;
+		case POTION:
+		case SCROLL:
+		case STICK:
+		case RING:
+		case AMULET:
+			return TRUE;
+	}
+	return FALSE;
+}
+
+
+/*
+ * killed:
+ *	Called to put a monster to death
+ */
+killed(item, pr)
+struct linked_list *item;
+bool pr;
+{
+	reg struct thing *tp;
+	reg struct object *obj;
+	struct linked_list *pitem, *nexti, *itspack;
+	struct coord here;
+	
+	nochange = FALSE;
+	tp = THINGPTR(item);
+	here = tp->t_pos;
+	if (pr) {
+		addmsg("Defeated ");
+		if (pl_on(ISBLIND))
+			msg("it.");
+		else
+			msg("%s.", monsters[tp->t_indx].m_name);
+	}
+	him->s_exp += tp->t_stats.s_exp;
+	isfight = FALSE;
+	check_level();
+	unhold(tp->t_type);					/* free player if held */
+	if (tp->t_type == 'L') {
+		reg struct room *rp;
+
+		rp = roomin(&here);
+		if (rp != NULL) {
+			if (rp->r_goldval!=0 || fallpos(&here, &rp->r_gold, FALSE)) {
+				rp->r_goldval += GOLDCALC;
+				if (!save_throw(VS_MAGIC,tp))
+					rp->r_goldval += GOLDCALC + GOLDCALC + GOLDCALC
+								   + GOLDCALC + GOLDCALC;
+				mvaddch(rp->r_gold.y, rp->r_gold.x, GOLD);
+				if (!rf_on(rp,ISDARK)) {
+					light(&hero);
+					mvwaddch(cw, hero.y, hero.x, PLAYER);
+				}
+			}
+		}
+	}
+	pitem = tp->t_pack;
+	itspack = tp->t_pack;
+	remove_monster(&here, item);
+	while (pitem != NULL) {
+		nexti = next(pitem);
+		obj = OBJPTR(pitem);
+		obj->o_pos = here;
+		detach(itspack, pitem);
+		fall(pitem, FALSE);
+		pitem = nexti;
+	}
+}