diff arogue7/player.c @ 125:adfa37e67084

Import Advanced Rogue 7.7 from the Roguelike Restoration Project (r1490)
author John "Elwin" Edwards
date Fri, 08 May 2015 15:24:40 -0400
parents
children f9ef86cf22b2
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arogue7/player.c	Fri May 08 15:24:40 2015 -0400
@@ -0,0 +1,812 @@
+/*
+ * player.c  -  This file contains functions for dealing with special player 
+ * abilities
+ *
+ * Advanced Rogue
+ * Copyright (C) 1984, 1985, 1986 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.
+ */
+
+/*
+ * This file contains functions for dealing with special player abilities
+ */
+
+#include <ctype.h>
+#include "curses.h"
+#include "rogue.h"
+#ifdef PC7300
+#include "menu.h"
+#endif
+
+
+/*
+ * affect:
+ *	cleric affecting undead
+ */
+
+affect()
+{
+    register struct linked_list *item;
+    register struct thing *tp;
+    register char *mname;
+    bool see;
+    coord new_pos;
+    int lvl;
+
+    if (!(player.t_ctype == C_CLERIC  ||
+          (player.t_ctype == C_PALADIN && pstats.s_lvl > 4) ||
+	  cur_relic[HEIL_ANKH] != 0)) {
+	msg("You cannot affect undead.");
+	return;
+    }
+
+    new_pos.y = hero.y + player.t_newpos.y;
+    new_pos.x = hero.x + player.t_newpos.x;
+
+    if (cansee(new_pos.y, new_pos.x)) see = TRUE;
+    else see = FALSE;
+
+    /* Anything there? */
+    if (new_pos.y < 0 || new_pos.y > lines-3 ||
+	new_pos.x < 0 || new_pos.x > cols-1 ||
+	mvwinch(mw, new_pos.y, new_pos.x) == ' ') {
+	msg("Nothing to affect.");
+	return;
+    }
+
+    if ((item = find_mons(new_pos.y, new_pos.x)) == NULL) {
+	debug("Affect what @ %d,%d?", new_pos.y, new_pos.x);
+	return;
+    }
+    tp = THINGPTR(item);
+    mname = monster_name(tp);
+
+    if (on(player, ISINVIS) && off(*tp, CANSEE)) {
+	msg("%s%s cannot see you", see ? "The " : "It",
+	    see ? mname : "");
+	return;
+    }
+
+    if (off(*tp, TURNABLE) || on(*tp, WASTURNED)) 
+	goto annoy;
+    turn_off(*tp, TURNABLE);
+
+    lvl = pstats.s_lvl;
+    if (player.t_ctype == C_PALADIN && cur_relic[HEIL_ANKH] == 0) {
+	lvl -= 4;
+    }
+    /* Can cleric kill it? */
+    if (lvl >= 3 * tp->t_stats.s_lvl) {
+	unsigned long test;	/* For overflow check */
+
+	msg("You have destroyed %s%s.", see ? "the " : "it", see ? mname : "");
+	test = pstats.s_exp + tp->t_stats.s_exp;
+
+	/* Be sure there is no overflow before increasing experience */
+	if (test > pstats.s_exp) pstats.s_exp = test;
+	killed(item, FALSE, TRUE, TRUE);
+	check_level();
+	return;
+    }
+
+    /* Can cleric turn it? */
+    if (rnd(100) + 1 >
+	 (100 * ((2 * tp->t_stats.s_lvl) - lvl)) / lvl) {
+	unsigned long test;	/* Overflow test */
+
+	/* Make the monster flee */
+	turn_on(*tp, WASTURNED);	/* No more fleeing after this */
+	turn_on(*tp, ISFLEE);
+	runto(tp, &hero);
+
+	/* Disrupt it */
+	dsrpt_monster(tp, TRUE, TRUE);
+
+	/* Let player know */
+	msg("You have turned %s%s.", see ? "the " : "it", see ? mname : "");
+
+	/* get points for turning monster -- but check overflow first */
+	test = pstats.s_exp + tp->t_stats.s_exp/2;
+	if (test > pstats.s_exp) pstats.s_exp = test;
+	check_level();
+
+	/* 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);
+
+	/* It is okay to turn tail */
+	tp->t_oldpos = tp->t_pos;
+
+	return;
+    }
+
+    /* Otherwise -- no go */
+annoy:
+    if (see && tp->t_stats.s_intel > 16)
+	msg("%s laughs at you...", prname(mname, TRUE));
+    else
+	msg("You do not affect %s%s.", see ? "the " : "it", see ? mname : "");
+
+    /* Annoy monster */
+   if (off(*tp, ISFLEE)) runto(tp, &hero);
+}
+
+/*
+ * the magic user is going to try and cast a spell
+ */
+cast()
+{
+    int		spell_ability,
+		which_spell,
+		num_spells;
+
+    if (player.t_ctype != C_MAGICIAN && player.t_ctype != C_RANGER) {
+	msg("You are not permitted to cast spells.");
+	return;
+    }
+    spell_ability = pstats.s_lvl * pstats.s_intel;
+    if (player.t_ctype != C_MAGICIAN)
+	spell_ability /= 3;
+
+    if (player.t_action != C_CAST) {
+	/* 
+	 * Get the number of avilable spells 
+	 */
+	num_spells = 0;
+	if (pstats.s_intel >= 16) 
+	    num_spells += pstats.s_intel - 15;
+	num_spells += pstats.s_lvl;
+	if (player.t_ctype != C_MAGICIAN) 
+	    num_spells /= 3;
+	if (num_spells > MAXSPELLS)	  
+	    num_spells = MAXSPELLS;
+	if (num_spells < 1) {
+	    msg("You are not allowed to cast spells yet.");
+	    return;
+	}
+	if (pick_spell(	magic_spells, 
+			spell_ability, 
+			num_spells, 
+			spell_power,
+			"cast",
+			"spell"))
+	    player.t_action = C_CAST;
+	return;
+    }
+
+    /* We've waited our required casting time. */
+    which_spell = player.t_selection;
+    player.t_selection = 0;
+    player.t_using = NULL;
+    player.t_action = A_NIL;
+
+    if ((spell_power + magic_spells[which_spell].s_cost) > spell_ability) {
+	msg("Your attempt fails.");
+	return;
+    }
+
+    msg("Your spell is successful.");
+
+    if (magic_spells[which_spell].s_type == TYP_POTION)
+        quaff(	magic_spells[which_spell].s_which,
+		NULL,
+        	magic_spells[which_spell].s_flag,
+		FALSE);
+    else if (magic_spells[which_spell].s_type == TYP_SCROLL)
+        read_scroll(	magic_spells[which_spell].s_which,
+        		magic_spells[which_spell].s_flag,
+			FALSE);
+    else if (magic_spells[which_spell].s_type == TYP_STICK) {
+	 if (!player_zap(magic_spells[which_spell].s_which,
+			 magic_spells[which_spell].s_flag)) {
+	     after = FALSE;
+	     return;
+	 }
+    }
+    spell_power += magic_spells[which_spell].s_cost;
+}
+
+/* 
+ * the druid asks his deity for a spell
+ */
+chant()
+{
+    register int	num_chants, 
+			chant_ability, 
+			which_chant;
+
+    which_chant = num_chants = chant_ability = 0;
+
+    if (player.t_ctype != C_DRUID && player.t_ctype != C_RANGER) {
+	msg("You are not permitted to chant.");
+	return;
+    }
+    if (cur_misc[WEAR_CLOAK] != NULL &&
+	cur_misc[WEAR_CLOAK]->o_which == MM_R_POWERLESS) {
+	msg("You can't seem to chant!");
+	return;
+    }
+    chant_ability = pstats.s_lvl * pstats.s_wisdom;
+    if (player.t_ctype != C_DRUID)
+	chant_ability /= 3;
+
+    if (player.t_action != C_CHANT) {
+	num_chants = 0;
+
+	/* Get the number of avilable chants */
+	if (pstats.s_wisdom > 16) 
+	    num_chants = (pstats.s_wisdom - 15) / 2;
+
+	num_chants += pstats.s_lvl;
+
+	if (player.t_ctype != C_DRUID) 
+	    num_chants /= 3;
+
+	if (num_chants > MAXCHANTS) 
+	    num_chants = MAXCHANTS;
+
+	if (num_chants < 1) {
+	    msg("You are not permitted to chant yet.");
+	    return;
+	}
+
+	/* Prompt for chant */
+	if (pick_spell(	druid_spells, 
+			chant_ability, 
+			num_chants, 
+			chant_time,
+			"sing",
+			"chant"))
+	    player.t_action = C_CHANT;
+
+	return;
+    }
+
+    /* We've waited our required chanting time. */
+    which_chant = player.t_selection;
+    player.t_selection = 0;
+    player.t_using = NULL;
+    player.t_action = A_NIL;
+
+    if (druid_spells[which_chant].s_cost + chant_time > chant_ability) {
+	msg("Your chant fails.");
+	return;
+    }
+
+    msg("Your chant has been granted.");
+
+    if (druid_spells[which_chant].s_type == TYP_POTION)
+	quaff(		druid_spells[which_chant].s_which,
+			NULL,
+			druid_spells[which_chant].s_flag,
+			FALSE);
+    else if (druid_spells[which_chant].s_type == TYP_SCROLL)
+	read_scroll(	druid_spells[which_chant].s_which,
+			druid_spells[which_chant].s_flag,
+			FALSE);
+    else if (druid_spells[which_chant].s_type == TYP_STICK) {
+	 if (!player_zap(druid_spells[which_chant].s_which,
+			 druid_spells[which_chant].s_flag)) {
+	     after = FALSE;
+	     return;
+	 }
+    }
+    chant_time += druid_spells[which_chant].s_cost;
+}
+
+/* Constitution bonus */
+
+const_bonus()	/* Hit point adjustment for changing levels */
+{
+    register int bonus;
+    if (pstats.s_const > 6 && pstats.s_const <= 14) 
+	bonus = 0;
+    else if (pstats.s_const > 14) 
+	bonus = pstats.s_const-14;
+    else if (pstats.s_const > 3) 
+	bonus = -1;
+    else
+	bonus = -2;
+    switch(player.t_ctype) {
+	case C_FIGHTER:		bonus = min(bonus, 11);
+	when C_MAGICIAN:	bonus = min(bonus, 4);
+	when C_CLERIC:		bonus = min(bonus, 4);
+	when C_THIEF:		bonus = min(bonus, 4);
+	when C_RANGER:		bonus = min(bonus, 6);
+	when C_PALADIN:		bonus = min(bonus, 8);
+	when C_ASSASIN:		bonus = min(bonus, 4);
+	when C_MONK:		bonus = min(bonus, 6);
+	when C_DRUID:		bonus = min(bonus, 4);
+	otherwise:		bonus = min(bonus, 4);
+    }
+    return(bonus);
+}
+
+
+/* Routines for thieves */
+
+/*
+ * gsense:
+ *	Sense gold
+ */
+
+gsense()
+{
+    /* Only thieves can do this */
+    if (player.t_ctype != C_THIEF && player.t_ctype != C_ASSASIN) {
+	msg("You seem to have no gold sense.");
+	return;
+    }
+
+    read_scroll(S_GFIND, NULL, FALSE);
+}
+
+/* 
+ * the cleric asks his deity for a spell
+ */
+pray()
+{
+    register int	num_prayers, 
+			prayer_ability, 
+			which_prayer;
+
+    which_prayer = num_prayers = prayer_ability =  0;
+
+    if (player.t_ctype != C_CLERIC  && 
+	player.t_ctype != C_PALADIN &&
+	cur_relic[HEIL_ANKH] == 0) {
+	    msg("You are not permitted to pray.");
+	    return;
+    }
+    if (cur_misc[WEAR_CLOAK] != NULL &&
+	cur_misc[WEAR_CLOAK]->o_which == MM_R_POWERLESS) {
+	msg("You can't seem to pray!");
+	return;
+    }
+
+    prayer_ability = pstats.s_lvl * pstats.s_wisdom;
+    if (player.t_ctype != C_CLERIC)
+	prayer_ability /= 3;
+
+    if (cur_relic[HEIL_ANKH]) prayer_ability *= 2;
+
+    if (player.t_action != C_PRAY) {
+	num_prayers = 0;
+
+	/* Get the number of avilable prayers */
+	if (pstats.s_wisdom > 16) 
+	    num_prayers += (pstats.s_wisdom - 15) / 2;
+
+	num_prayers += pstats.s_lvl;
+	if (cur_relic[HEIL_ANKH]) num_prayers += 3;
+
+	if (player.t_ctype != C_CLERIC) 
+	    num_prayers /= 3;
+
+	if (num_prayers > MAXPRAYERS) 
+	    num_prayers = MAXPRAYERS;
+	if (num_prayers < 1) {
+	    msg("You are not permitted to pray yet.");
+	    return;
+	}
+
+	/* Prompt for prayer */
+	if (pick_spell(	cleric_spells, 
+			prayer_ability, 
+			num_prayers, 
+			pray_time,
+			"offer",
+			"prayer"))
+	    player.t_action = C_PRAY;
+
+	return;
+    }
+
+    /* We've waited our required praying time. */
+    which_prayer = player.t_selection;
+    player.t_selection = 0;
+    player.t_using = NULL;
+    player.t_action = A_NIL;
+
+    if (cleric_spells[which_prayer].s_cost + pray_time > prayer_ability) {
+	msg("Your prayer fails.");
+	return;
+    }
+
+    msg("Your prayer has been granted.");
+
+    if (cleric_spells[which_prayer].s_type == TYP_POTION)
+	quaff(		cleric_spells[which_prayer].s_which,
+			NULL,
+			cleric_spells[which_prayer].s_flag,
+			FALSE);
+    else if (cleric_spells[which_prayer].s_type == TYP_SCROLL)
+	read_scroll(	cleric_spells[which_prayer].s_which,
+			cleric_spells[which_prayer].s_flag,
+			FALSE);
+    else if (cleric_spells[which_prayer].s_type == TYP_STICK) {
+	 if (!player_zap(cleric_spells[which_prayer].s_which,
+			 cleric_spells[which_prayer].s_flag)) {
+	     after = FALSE;
+	     return;
+	 }
+    }
+    pray_time += cleric_spells[which_prayer].s_cost;
+}
+
+
+
+/*
+ * steal:
+ *	Steal in direction given in delta
+ */
+
+steal()
+{
+    register struct linked_list *item;
+    register struct thing *tp;
+    register char *mname;
+    coord new_pos;
+    int thief_bonus = -50;
+    bool isinvisible = FALSE;
+
+    if (player.t_ctype != C_THIEF && player.t_ctype != C_ASSASIN) {
+	msg("Only thieves and assassins can steal.");
+	return;
+    }
+    if (on(player, ISBLIND)) {
+	msg("You can't see anything.");
+	return;
+    }
+
+    new_pos.y = hero.y + player.t_newpos.y;
+    new_pos.x = hero.x + player.t_newpos.x;
+
+    /* Anything there? */
+    if (new_pos.y < 0 || new_pos.y > lines-3 ||
+	new_pos.x < 0 || new_pos.x > cols-1 ||
+	mvwinch(mw, new_pos.y, new_pos.x) == ' ') {
+	msg("Nothing to steal from.");
+	return;
+    }
+
+    if ((item = find_mons(new_pos.y, new_pos.x)) == NULL)
+	debug("Steal from what @ %d,%d?", new_pos.y, new_pos.x);
+    tp = THINGPTR(item);
+    if (on(*tp, ISSTONE)) {
+	msg ("You can't steal from stone!");
+	return;
+    }
+    if (isinvisible = invisible(tp)) mname = "creature";
+    else mname = monster_name(tp);
+
+    /* Can player steal something unnoticed? */
+    if (player.t_ctype == C_THIEF) thief_bonus = 10;
+    if (player.t_ctype == C_ASSASIN) thief_bonus = 0;
+    if (on(*tp, ISUNIQUE)) thief_bonus -= 15;
+    if (isinvisible) thief_bonus -= 20;
+    if (on(*tp, ISINWALL) && off(player, CANINWALL)) thief_bonus -= 50;
+
+    if (on(*tp, ISHELD) || tp->t_action == A_FREEZE ||
+	rnd(100) <
+	(thief_bonus + 2*dex_compute() + 5*pstats.s_lvl -
+	 5*(tp->t_stats.s_lvl - 3))) {
+	register struct linked_list *s_item, *pack_ptr;
+	int count = 0;
+	unsigned long test;	/* Overflow check */
+
+	s_item = NULL;	/* Start stolen goods out as nothing */
+
+	/* Find a good item to take */
+	for (pack_ptr=tp->t_pack; pack_ptr != NULL; pack_ptr=next(pack_ptr))
+	    if ((OBJPTR(pack_ptr))->o_type != RELIC &&
+		pack_ptr != tp->t_using &&  /* Monster can't be using it */
+		rnd(++count) == 0)
+		s_item = pack_ptr;
+
+	/* 
+	 * Find anything?
+	 */
+	if (s_item == NULL) {
+	    msg("%s apparently has nothing to steal.", prname(mname, TRUE));
+	    return;
+	}
+
+	/* Take it from monster */
+	if (tp->t_pack) detach(tp->t_pack, s_item);
+
+	/* Recalculate the monster's encumberance */
+	updpack(TRUE, tp);
+
+	/* Give it to player */
+	if (add_pack(s_item, FALSE, NULL) == FALSE) {
+	   (OBJPTR(s_item))->o_pos = hero;
+	   fall(s_item, TRUE);
+	}
+
+	/* Get points for stealing -- but first check for overflow */
+	test = pstats.s_exp + tp->t_stats.s_exp/2;
+	if (test > pstats.s_exp) pstats.s_exp = test;
+
+	/*
+	 * Do adjustments if player went up a level
+	 */
+	check_level();
+    }
+
+    else {
+	msg("Your attempt fails.");
+
+	/* Annoy monster (maybe) */
+	if (rnd(35) >= dex_compute() + thief_bonus) {
+	    /*
+	     * If this is a charmed creature, there is a chance it
+	     * will become uncharmed.
+	     */
+	    if (on(*tp, ISCHARMED) && save(VS_MAGIC, tp, 0)) {
+		msg("The eyes of %s turn clear.", prname(mname, FALSE));
+		turn_off(*tp, ISCHARMED);
+	    }
+	    if (on(*tp, CANSELL)) {
+		turn_off(*tp, CANSELL);
+		tp->t_action = A_NIL;
+		tp->t_movement = 0;
+		if (rnd(100) < 50) /* make him steal something */
+		    turn_on(*tp, STEALMAGIC);
+		else
+		    turn_on(*tp, STEALGOLD);
+		if (!isinvisible)
+		    msg("%s looks insulted.", prname(mname, TRUE));
+	    }
+	    runto(tp, &hero);
+	}
+    }
+}
+
+#ifdef PC7300
+/* Use MAXSPELLS or whatever is the biggest number of spells/prayers/etc */
+static menu_t Display;				/* The menu structure */
+static mitem_t Dispitems[MAXSPELLS+1];		/* Info for each line */
+static char Displines[MAXSPELLS+1][LINELEN+1];	/* The lines themselves */
+#endif
+
+/*
+ * this routine lets the player pick the spell that they
+ * want to cast regardless of character class
+ */
+pick_spell(spells, ability, num_spells, power, prompt, type)
+struct spells	spells[];	/* spell list				 */
+int		ability;	/* spell ability			 */
+int		num_spells;	/* number of spells that can be cast	 */
+int		power;		/* spell power				 */
+char		*prompt;	/* prompt for spell list		 */
+char		*type;		/* type of thing--> spell, prayer, chant */
+{
+    bool		nohw = FALSE;
+    register int	i;
+    int			curlen,
+			maxlen,
+			dummy,
+			which_spell,
+			spell_left;
+#ifdef PC7300
+    char label[LINELEN],	/* For menu label */
+	 title[LINELEN];	/* For menu title */
+#endif
+
+    if (cur_misc[WEAR_CLOAK] != NULL &&
+	cur_misc[WEAR_CLOAK]->o_which == MM_R_POWERLESS) {
+	msg("You can't seem to start a %s!", type);
+	return(FALSE);
+    }
+
+    /* Prompt for spells */
+    msg("Which %s are you %sing? (* for list): ", type, prompt);
+
+    which_spell = (int) (readchar() - 'a');
+    msg("");	/* Get rid of the prompt */
+    if (which_spell == (int) ESCAPE - (int) 'a') {
+	after = FALSE;
+	return(FALSE);
+    }
+    if (which_spell >= 0 && which_spell < num_spells) nohw = TRUE;
+
+    else if (slow_invent) {
+	register char c;
+
+	nohw = TRUE;
+	do {
+	    for (i=0; i<num_spells; i++) {
+		msg("");
+		mvwaddch(msgw, 0, 0, '[');
+		waddch(msgw, (char) ((int) 'a' + i));
+		wprintw(msgw, "] A %s of ", type);
+		if (spells[i].s_type == TYP_POTION)
+		    waddstr(msgw, p_magic[spells[i].s_which].mi_name);
+		else if (spells[i].s_type == TYP_SCROLL)
+		    waddstr(msgw, s_magic[spells[i].s_which].mi_name);
+		else if (spells[i].s_type == TYP_STICK)
+		    waddstr(msgw, ws_magic[spells[i].s_which].mi_name);
+		waddstr(msgw, morestr);
+	        wclrtobot(msgw);
+		clearok(msgw, FALSE);
+		draw(msgw);
+		do {
+		    c = readchar();
+		} while (c != ' ' && c != ESCAPE);
+		if (c == ESCAPE)
+		    break;
+	    }
+	    msg("");
+	    wmove(msgw, 0, 0);
+	    wprintw(msgw, "Which %s are you %sing? ", type, prompt);
+	    clearok(msgw, FALSE);
+	    draw(msgw);
+
+	    which_spell = (int) (readchar() - 'a');
+	} while (which_spell != (int) (ESCAPE - 'a') &&
+		 (which_spell < 0 || which_spell >= num_spells));
+
+	if (which_spell == (int) (ESCAPE - 'a')) {
+	    mpos = 0;
+	    msg("");
+	    after = FALSE;
+	    return(FALSE);
+	}
+    }
+    else {
+	/* Now display the possible spells */
+	wclear(hw);