diff arogue7/misc.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 b786053d2f37
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arogue7/misc.c	Fri May 08 15:24:40 2015 -0400
@@ -0,0 +1,1202 @@
+/*
+ * misc.c - routines dealing specifically with miscellaneous magic
+ *
+ * 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.
+ */
+
+#include "curses.h"
+#include <ctype.h>
+#include "rogue.h"
+#ifdef PC7300
+#include "menu.h"
+#endif
+
+/*
+ * routines dealing specifically with miscellaneous magic
+ */
+
+/*
+ * changeclass:
+ *	Change the player's class to the specified one.
+ */
+
+changeclass(newclass)
+int newclass;
+{
+    if (newclass == player.t_ctype) {
+	msg("You feel more skillful.");
+	raise_level();
+    }
+    else {
+	/*
+	 * reset his class and then use check_level to reset hit
+	 * points and the right level for his exp pts
+	 * drop exp pts by 10%
+	 */
+	long save;
+
+	msg("You feel like a whole new person!");
+
+	/*
+	 * if he becomes a thief he has to have leather armor
+	 */
+	if ((newclass == C_THIEF || newclass == C_ASSASIN)	&&
+	    cur_armor != NULL					&&
+	    cur_armor->o_which != LEATHER			&&
+	    cur_armor->o_which != STUDDED_LEATHER ) 
+		cur_armor->o_which = STUDDED_LEATHER;
+	/*
+	 * if he becomes a monk he can't wear armor
+	 */
+	if (newclass == C_MONK && cur_armor != NULL) {
+		cur_armor->o_ac = armors[cur_armor->o_which].a_class - 
+				  cur_armor->o_ac;
+		cur_armor->o_type = MM;
+		cur_armor->o_which = MM_PROTECT;
+		cur_armor->o_flags &= ~(ISPROT | ISKNOW | ISMETAL);
+		cur_misc[WEAR_CLOAK] = cur_armor;
+		cur_armor = NULL;
+	}
+	/*
+	 * if he used to be a spell caster of some sort, kill the fuse
+	 */
+	if (player.t_ctype == C_MAGICIAN || player.t_ctype == C_RANGER)
+		extinguish(spell_recovery);
+	if (player.t_ctype == C_DRUID || player.t_ctype == C_RANGER)
+		extinguish(chant_recovery);
+	if ((player.t_ctype == C_CLERIC || player.t_ctype == C_PALADIN) &&
+	     !cur_relic[HEIL_ANKH])
+		extinguish(prayer_recovery);
+	/*
+	 * if he becomes a spell caster of some kind, give him a fuse
+	 */
+	if (newclass == C_MAGICIAN || newclass == C_RANGER)
+		fuse(spell_recovery, 0, SPELLTIME, AFTER);
+	if (newclass == C_DRUID || newclass == C_RANGER)
+		fuse(chant_recovery, 0, SPELLTIME, AFTER);
+	if ((newclass==C_CLERIC || newclass==C_PALADIN) && !cur_misc[HEIL_ANKH])
+		fuse(prayer_recovery, 0, SPELLTIME, AFTER);
+	/*
+	 * if he's changing from a fighter then may have to change
+	 * his sword since only fighter can use two-handed
+	 * and bastard swords
+	 */
+	if ((player.t_ctype == C_FIGHTER	||
+	     player.t_ctype == C_RANGER		||
+	     player.t_ctype == C_PALADIN)		&&
+	    cur_weapon != NULL				&&
+	    cur_weapon->o_type == WEAPON		&&
+	   (cur_weapon->o_which== BASWORD	||
+	    cur_weapon->o_which== TWOSWORD )		&&
+	   !(newclass == C_FIGHTER		||
+	     newclass == C_RANGER		||
+	     newclass == C_PALADIN)			&&
+	   !(newclass == C_ASSASIN		&&
+	     cur_weapon->o_which == BASWORD))
+		cur_weapon->o_which = SWORD;
+
+	/*
+	 * if he was a thief then take out the trap_look() daemon
+	 */
+	if (player.t_ctype == C_THIEF || 
+	    player.t_ctype == C_MONK  ||
+	    player.t_ctype == C_ASSASIN)
+	    kill_daemon(trap_look);
+
+	/*
+	 * if he becomes a thief then add the trap_look() daemon
+	 */
+	if (newclass == C_THIEF || newclass == C_ASSASIN || newclass == C_MONK)
+	    daemon(trap_look, 0, AFTER);
+	char_type = player.t_ctype = newclass;
+	save = pstats.s_hpt;
+	max_stats.s_hpt = pstats.s_hpt = 0;
+	max_stats.s_lvl = pstats.s_lvl = 0; 
+	max_stats.s_lvladj = pstats.s_lvladj = 0; 
+	max_stats.s_exp = pstats.s_exp -= pstats.s_exp/10;
+	check_level();
+	if (pstats.s_hpt > save) /* don't add to current hits */
+	    pstats.s_hpt = save;
+    }
+}
+
+/*
+ * Use the relic that our monster is wielding.
+ */
+m_use_relic(monster)
+register struct thing *monster;
+{
+    register struct object *obj;
+
+    /* Make sure we really have it */
+    if (monster->t_using) obj = OBJPTR(monster->t_using);
+    else {
+	debug("Relic not set!");
+	monster->t_action = A_NIL;
+	return;
+    }
+
+    /* Now let's see what we're using */
+    if (obj->o_type == RELIC) switch (obj->o_which) {
+	case MING_STAFF: {
+	    static struct object missile = {
+	      MISSILE, {0,0}, "", 0, "", "0d4 " , NULL, 0, WS_MISSILE, 100, 1
+	    };
+
+	    debug("Firing Ming's staff");
+	    sprintf(missile.o_hurldmg, "%dd4", monster->t_stats.s_lvl);
+	    do_motion(&missile,
+		       monster->t_newpos.y, monster->t_newpos.x, monster);
+	    hit_monster(unc(missile.o_pos), &missile, monster);
+	    monster->t_artifact = monster->t_artifact * 4 / 5;
+	}
+	when EMORI_CLOAK:
+	    debug("stunning with Emori's cloak");
+	    do_zap(monster, obj, &monster->t_newpos, WS_PARALYZE, NULL);
+	    obj->o_charges = 0;
+
+	when ASMO_ROD: {
+	    char *name;
+
+	    switch (rnd(3)) { /* Select a function */
+		case 0:	   name = "lightning bolt";
+		when 1:	   name = "flame";
+		otherwise: name = "ice";
+	    }
+	    shoot_bolt(	monster, 
+			monster->t_pos, 
+			monster->t_newpos, 
+			FALSE, 
+			monster->t_index, 
+			name, 
+			roll(monster->t_stats.s_lvl,6));
+	    monster->t_artifact /= 2;
+	}
+	when BRIAN_MANDOLIN:
+	    /* Make sure the defendant is still around */
+	    if (DISTANCE(monster->t_pos.y, monster->t_pos.x,
+			 hero.y, hero.x) < 25) {
+		if (!save(VS_MAGIC, &player, -4) &&
+		    !ISWEARING(R_ALERT)) {
+		    msg("Some beautiful music enthralls you.");
+		    player.t_no_move += movement(&player) * FREEZETIME;
+		    player.t_action = A_FREEZE;
+		    monster->t_artifact = monster->t_artifact * 2 / 3;
+		}
+		else {
+		    msg("You wince at a sour note.");
+		    monster->t_artifact /= 3;
+		}
+	    }
+	when GERYON_HORN:
+	    /* Make sure the defendant is still around */
+	    if (DISTANCE(monster->t_pos.y, monster->t_pos.x,
+			 hero.y, hero.x) < 25) {
+		if (!ISWEARING(R_HEROISM) &&
+		    !save(VS_MAGIC, &player, -4)) {
+			turn_on(player, ISFLEE);
+			player.t_dest = &monster->t_pos;
+			msg("A shrill blast terrifies you.");
+			monster->t_artifact = monster->t_artifact * 3 / 4;
+		}
+		else  {
+		    msg("A shrill blast sends chills up your spine.");
+		    monster->t_artifact /= 3;
+		}
+	    }
+
+	otherwise:
+	    /* Unknown RELIC! */
+	    debug("Unknown wielded relic %d", obj->o_which);
+    }
+    else debug("Declared relic is %d", obj->o_type);
+
+    turn_off(*monster, CANSURPRISE);
+    /* Reset the monsters actions */
+    monster->t_action = A_NIL;
+    monster->t_using = NULL;
+}
+ 
+/*
+ * add something to the contents of something else
+ */
+put_contents(bag, item)
+register struct object *bag;		/* the holder of the items */
+register struct linked_list *item;	/* the item to put inside  */
+{
+    register struct linked_list *titem;
+    register struct object *tobj;
+
+    bag->o_ac++;
+    tobj = OBJPTR(item);
+    for (titem = bag->contents; titem != NULL; titem = next(titem)) {
+	if ((OBJPTR(titem))->o_which == tobj->o_which)
+	    break;
+    }
+    if (titem == NULL) {	/* if not a duplicate put at beginning */
+	attach(bag->contents, item);
+    }
+    else {
+	item->l_prev = titem;
+	item->l_next = titem->l_next;
+	if (next(titem) != NULL) 
+	    (titem->l_next)->l_prev = item;
+	titem->l_next = item;
+    }
+}
+
+/*
+ * remove something from something else
+ */
+take_contents(bag, item)
+register struct object *bag;		/* the holder of the items */
+register struct linked_list *item;
+{
+
+    if (bag->o_ac <= 0) {
+	msg("Nothing to take out");
+	return;
+    }
+    bag->o_ac--;
+    detach(bag->contents, item);
+    if (!add_pack(item, FALSE, NULL))
+	put_contents(bag, item);
+}
+
+
+do_bag(item)
+register struct linked_list *item;
+{
+
+    register struct linked_list *titem;
+    register struct object *obj, *tobj;
+    bool doit = TRUE;
+
+    obj = OBJPTR(item);
+    while (doit) {
+	msg("What do you want to do? (* for a list): ");
+	mpos = 0;
+	switch (readchar()) {
+	    case EOF:
+	    case ESCAPE:
+		msg ("");
+		doit = FALSE;
+	    when '1':
+		inventory(obj->contents, ALL);
+
+	    when '2':
+		if (obj->o_ac >= MAXCONTENTS) {
+		    msg("the %s is full", m_magic[obj->o_which].mi_name);
+		    break;
+		}
+		switch (obj->o_which) {
+		case MM_BEAKER:
+		    titem = get_item(pack, "put in", POTION, FALSE, FALSE);
+		when MM_BOOK:
+		    titem = get_item(pack, "put in", SCROLL, FALSE, FALSE);
+		}
+		if (titem == NULL)
+		    break;
+		detach(pack, titem);
+		inpack--;
+		put_contents(obj, titem);
+	    
+	    when '3':
+		titem = get_item(obj->contents,"take out",ALL,FALSE,FALSE);
+		if (titem == NULL)
+		    break;
+		take_contents(obj, titem);
+		
+	    when '4': 
+		switch (obj->o_which) {
+		case MM_BEAKER: 
+		    titem = get_item(obj->contents,"quaff",ALL,FALSE,FALSE);
+		    if (titem == NULL)
+			break;
+		    tobj = OBJPTR(titem);
+		    obj->o_ac--;
+		    detach(obj->contents, titem);
+		    quaff(tobj->o_which, 
+			  tobj->o_kind,
+			  tobj->o_flags,
+			  TRUE);
+		    if (p_know[tobj->o_which] && p_guess[tobj->o_which])
+		    {
+			free(p_guess[tobj->o_which]);
+			p_guess[tobj->o_which] = NULL;
+		    }
+		    else if (!p_know[tobj->o_which]		&& 
+			     askme				&&
+			     (tobj->o_flags & ISKNOW) == 0	&&
+			     (tobj->o_flags & ISPOST) == 0	&&
+			     p_guess[tobj->o_which] == NULL) {
+			nameitem(titem, FALSE);
+		    }
+		    o_discard(titem);
+		when MM_BOOK:   
+		    if (on(player, ISBLIND)) {
+			msg("You can't see to read anything");
+			break;
+		    }
+		    titem = get_item(obj->contents,"read",ALL,FALSE,FALSE);
+		    if (titem == NULL)
+			break;
+		    tobj = OBJPTR(titem);
+		    obj->o_ac--;
+		    detach(obj->contents, titem);
+		    read_scroll(tobj->o_which, 
+			        tobj->o_flags & (ISCURSED|ISBLESSED),
+				TRUE);
+		    if (s_know[tobj->o_which] && s_guess[tobj->o_which])
+		    {
+			free(s_guess[tobj->o_which]);
+			s_guess[tobj->o_which] = NULL;
+		    }
+		    else if (!s_know[tobj->o_which]		&& 
+			     askme				&&
+			     (tobj->o_flags & ISKNOW) == 0	&&
+			     (tobj->o_flags & ISPOST) == 0	&&
+			     s_guess[tobj->o_which] == NULL) {
+			nameitem(titem, FALSE);
+		    }
+		    o_discard(titem);
+		}
+		doit = FALSE;
+
+	    otherwise:
+		wclear(hw);
+		touchwin(hw);
+		mvwaddstr(hw,0,0,"The following operations are available:");
+		mvwaddstr(hw,2,0,"[1]\tInventory\n");
+		wprintw(hw,"[2]\tPut something in the %s\n",
+			m_magic[obj->o_which].mi_name);
+		wprintw(hw,"[3]\tTake something out of the %s\n",
+			m_magic[obj->o_which].mi_name);
+		switch(obj->o_which) {
+		    case MM_BEAKER: waddstr(hw,"[4]\tQuaff a potion\n");
+		    when MM_BOOK:   waddstr(hw,"[4]\tRead a scroll\n");
+		}
+		waddstr(hw,"[ESC]\tLeave this menu\n");
+		mvwaddstr(hw, lines-1, 0, spacemsg);
+		draw(hw);
+		wait_for (' ');
+		clearok(cw, TRUE);
+		touchwin(cw);
+	}
+    }
+}
+
+do_panic(who)
+int who;	/* Kind of monster to panic (all if who is NULL) */
+{
+    register int x,y;
+    register struct linked_list *mon, *item;
+    register struct thing *th;
+
+    for (x = hero.x-2; x <= hero.x+2; x++) {
+	for (y = hero.y-2; y <= hero.y+2; y++) {
+	    if (y < 1 || x < 0 || y > lines - 3  || x > cols - 1) 
+		continue;
+	    if (isalpha(mvwinch(mw, y, x))) {
+		if ((mon = find_mons(y, x)) != NULL) {
+		    th = THINGPTR(mon);
+
+		    /* Is this the right kind of monster to panic? */
+		    if (who && th->t_index != who) continue;
+
+		    if (who || 
+			(!on(*th, ISUNDEAD) && !save(VS_MAGIC, th, 0) && off(*th, WASTURNED))) {
+			msg("%s %s.", prname(monster_name(th), TRUE),
+			    terse ? "panics" : "turns to run in panic");
+
+			turn_on(*th, ISFLEE);
+			turn_on(*th, WASTURNED);
+			turn_off(*th, CANSURPRISE);
+
+			/* Disrupt what it was doing */
+			dsrpt_monster(th, TRUE, TRUE);
+
+			/* If monster was suffocating, stop it */
+			if (on(*th, DIDSUFFOCATE)) {
+			    turn_off(*th, DIDSUFFOCATE);
+			    extinguish(suffocate);
+			}
+
+			/* If monster held us, stop it */
+			if (on(*th, DIDHOLD) && (--hold_count == 0))
+				turn_off(player, ISHELD);
+			turn_off(*th, DIDHOLD);
+
+			/*
+			 * if he has something he might drop it
+			 */
+			if ((item = th->t_pack) != NULL		&& 
+			    (OBJPTR(item))->o_type != RELIC	&& 
+			    rnd(100) < 50) {
+				detach(th->t_pack, item);
+				fall(item, FALSE);
+			}
+
+			/* It is okay to turn tail */
+			th->t_oldpos = th->t_pos;
+		    }
+		    runto(th, &hero);
+		}
+	    }
+	}
+    }
+}
+
+/*
+ * print miscellaneous magic bonuses
+ */
+char *
+misc_name(obj)
+register struct object *obj;
+{
+    static char buf[LINELEN];
+    char buf1[LINELEN];
+
+    buf[0] = '\0';
+    buf1[0] = '\0';
+    if (!(obj->o_flags & ISKNOW))
+	return (m_magic[obj->o_which].mi_name);
+    switch (obj->o_which) {
+	case MM_BRACERS:
+	case MM_PROTECT:
+	    strcat(buf, num(obj->o_ac, 0));
+	    strcat(buf, " ");
+    }
+    switch (obj->o_which) {
+	case MM_G_OGRE:
+	case MM_G_DEXTERITY:
+	case MM_JEWEL:
+	case MM_STRANGLE:
+	case MM_R_POWERLESS:
+	case MM_DANCE:
+	    if (obj->o_flags & ISCURSED)
+		strcat(buf, "cursed ");
+    }
+    strcat(buf, m_magic[obj->o_which].mi_name);
+    switch (obj->o_which) {
+	case MM_JUG:
+	    if (obj->o_ac == JUG_EMPTY)
+		strcat(buf1, " [empty]");
+	    else if (p_know[obj->o_ac])
+		sprintf(buf1, " [containing a potion of %s (%s)]",
+			p_magic[obj->o_ac].mi_name,
+			p_colors[obj->o_ac]);
+	    else sprintf(buf1, " [containing a%s %s liquid]", 
+			vowelstr(p_colors[obj->o_ac]),
+			p_colors[obj->o_ac]);
+	when MM_BEAKER:		
+	case MM_BOOK: {
+	    sprintf(buf1, " [containing %d]", obj->o_ac);
+	}
+	when MM_OPEN:
+	case MM_HUNGER:
+	    sprintf(buf1, " [%d ring%s]", obj->o_charges, 
+			  obj->o_charges == 1 ? "" : "s");
+	when MM_DRUMS:
+	    sprintf(buf1, " [%d beat%s]", obj->o_charges, 
+			  obj->o_charges == 1 ? "" : "s");
+	when MM_DISAPPEAR:
+	case MM_CHOKE:
+	    sprintf(buf1, " [%d pinch%s]", obj->o_charges, 
+			  obj->o_charges == 1 ? "" : "es");
+	when MM_KEOGHTOM:
+	    sprintf(buf1, " [%d application%s]", obj->o_charges, 
+			  obj->o_charges == 1 ? "" : "s");
+	when MM_SKILLS:
+	    sprintf(buf1, " [%s]", char_class[obj->o_ac].name);
+    }
+    strcat (buf, buf1);
+    return buf;
+}
+
+use_emori()
+{
+    char selection;	/* Cloak function */
+    int state = 0;	/* Menu state */
+
+    msg("What do you want to do? (* for a list): ");
+    do {
+	selection = tolower(readchar());
+	switch (selection) {
+	    case '*':
+	      if (state != 1) {
+		wclear(hw);
+		touchwin(hw);
+		mvwaddstr(hw, 2, 0,  "[1] Fly\n[2] Stop flying\n");
+		waddstr(hw,	     "[3] Turn invisible\n[4] Turn Visible\n");
+		mvwaddstr(hw, 0, 0, "What do you want to do? ");
+		draw(hw);
+		state = 1;	/* Now in prompt window */
+	      }
+	      break;
+
+	    case ESCAPE:
+		if (state == 1) {
+		    clearok(cw, TRUE); /* Set up for redraw */
+		    touchwin(cw);
+		}
+		msg("");
+
+		after = FALSE;
+		return;
+
+	    when '1':
+	    case '2':
+	    case '3':
+	    case '4':
+		if (state == 1) {	/* In prompt window */
+		    clearok(cw, TRUE); /* Set up for redraw */
+		    touchwin(cw);
+		}
+
+		msg("");
+
+		state = 2;	/* Finished */
+		break;
+
+	    default:
+		if (state == 1) {	/* In the prompt window */
+		    mvwaddstr(hw, 0, 0,
+				"Please enter a selection between 1 and 4:  ");
+		    draw(hw);
+		}
+		else {	/* Normal window */
+		    mpos = 0;
+		    msg("Please enter a selection between 1 and 4:  ");
+		}
+	}
+    } while (state != 2);
+
+    /* We now must have a selection between 1 and 4 */
+    switch (selection) {
+	case '1':	/* Fly */
+	    if (on(player, ISFLY)) {
+		extinguish(land);	/* Extinguish in case of potion */
+		msg("%slready flying.", terse ? "A" : "You are a");
+	    }
+	    else {
+		msg("You feel lighter than air!");
+		turn_on(player, ISFLY);
+	    }
+	when '2':	/* Stop flying */
+	    if (off(player, ISFLY))
+		msg("%sot flying.", terse ? "N" : "You are n");
+	    else {
+		if (find_slot(land))
+		    msg("%sot flying by the cloak.",
+			terse ? "N" : "You are n");
+		else land();
+	    }
+	when '3':	/* Turn invisible */
+	    if (off(player, ISINVIS)) {
+		turn_on(player, ISINVIS);
+		msg("You have a tingling feeling all over your body");
+		PLAYER = IPLAYER;
+		light(&hero);
+	    }
+	    else {
+		extinguish(appear);	/* Extinguish in case of potion */
+		extinguish(dust_appear);/* dust of disappearance        */
+		msg("%slready invisible.", terse ? "A" : "You are a");
+	    }
+	when '4':	/* Turn visible */
+	    if (off(player, ISINVIS))
+		msg("%sot invisible.", terse ? "N" : "You are n");
+	    else {
+		if (find_slot(appear) || find_slot(dust_appear))
+		    msg("%sot invisible by the cloak.",
+			terse ? "N" : "You are n");
+		else appear();
+	    }
+    }
+}
+
+#ifdef PC7300
+static menu_t Display;				/* The menu structure */
+static mitem_t Dispitems[MAXQUILL+1];		/* Info for each line */
+static char Displines[MAXQUILL+1][LINELEN+1];	/* The lines themselves */
+#endif
+/*
+ * try to write a scroll with the quill of Nagrom
+ */
+use_quill(obj)
+struct object *obj;
+{
+    struct linked_list	*item;
+    register int	i,
+			scroll_ability;
+    int			which_scroll,
+			curlen,
+			maxlen,
+			dummy;
+    bool		nohw = FALSE;
+
+    i = which_scroll = 0;
+    scroll_ability = obj->o_charges;
+
+    /* Prompt for scrolls */
+    msg("Which scroll are you writing? (* for list): ");
+
+    which_scroll = (int) (readchar() - 'a');
+    if (which_scroll == (int) ESCAPE - (int) 'a') {
+	mpos = 0;
+	msg("");
+	after = FALSE;