diff arogue5/misc.c @ 63:0ed67132cf10

Import Advanced Rogue 5.8 from the Roguelike Restoration Project (r1490)
author elwin
date Thu, 09 Aug 2012 22:58:48 +0000
parents
children c49f7927b0fa
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arogue5/misc.c	Thu Aug 09 22:58:48 2012 +0000
@@ -0,0 +1,736 @@
+/*
+ * routines dealing specifically with miscellaneous magic
+ *
+ * Advanced Rogue
+ * Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T
+ * All rights reserved.
+ *
+ * See the file LICENSE.TXT for full copyright and licensing information.
+ */
+
+#include "curses.h"
+#include <ctype.h>
+#include "rogue.h"
+
+/*
+ * See if a monster has some magic it can use.  Use it and return TRUE if so.
+ */
+bool
+m_use_item(monster, monst_pos, defend_pos)
+register struct thing *monster;
+register coord *monst_pos, *defend_pos;
+{
+    register struct linked_list *pitem;
+    register struct object *obj;
+    register coord *shoot_dir = can_shoot(monst_pos, defend_pos);
+    int dist=DISTANCE(monst_pos->y, monst_pos->x, defend_pos->y, defend_pos->x);
+
+    for (pitem=monster->t_pack; pitem; pitem=next(pitem)) {
+	obj = OBJPTR(pitem);
+	if (obj->o_type != RELIC) continue;	/* Only care about relics now */
+	switch (obj->o_which) {
+	    case MING_STAFF: {
+		static struct object missile = {
+		  MISSILE, {0,0}, "", 0, "", "0d4 " , NULL, 0, WS_MISSILE, 100, 1
+		};
+
+		if (shoot_dir != NULL) {
+		    sprintf(missile.o_hurldmg, "%dd4", monster->t_stats.s_lvl);
+		    do_motion(&missile, shoot_dir->y, shoot_dir->x, monster);
+		    hit_monster(unc(missile.o_pos), &missile, monster);
+		    return(TRUE);
+		}
+	    }
+	    when ASMO_ROD:
+		/* The bolt must be able to reach the defendant */
+		if (shoot_dir != NULL && dist < BOLT_LENGTH * BOLT_LENGTH) {
+		    char *name;
+
+		    switch (rnd(3)) { /* Select a function */
+			case 0:	   name = "lightning bolt";
+			when 1:	   name = "flame";
+			otherwise: name = "ice";
+		    }
+		    shoot_bolt(	monster, 
+				*monst_pos, 
+				*shoot_dir, 
+				FALSE, 
+				monster->t_index, 
+				name, 
+				roll(monster->t_stats.s_lvl,6));
+		    return(TRUE);
+		}
+	    when BRIAN_MANDOLIN:
+		/* The defendant must be the player and within 2 spaces */
+		if (ce(*defend_pos, hero) && dist < 9 && no_command == 0 &&
+		    rnd(100) < 33) {
+		    if (!save(VS_MAGIC, &player, -4) &&
+			!ISWEARING(R_ALERT)) {
+			msg("Some beautiful music enthralls you.");
+			no_command += FREEZETIME;
+		    }
+		    else msg("You wince at a sour note.");
+		    return(TRUE);
+		}
+	    when GERYON_HORN:
+		/* The defendant must be the player and within 2 spaces */
+		if (ce(*defend_pos, hero) && dist < 9 &&
+		    (off(player, ISFLEE) || player.t_dest != &monster->t_pos)
+		    && rnd(100) < 33) {
+		    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.");
+		    }
+		    else msg("A shrill blast sends chills up your spine.");
+		    return(TRUE);
+		}
+	}
+    }
+    return(FALSE);
+}
+ 
+/*
+ * 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 = NULL;
+    register struct object *obj;
+    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);
+		when MM_BOOK:   titem = get_item(pack, "put in", SCROLL);
+		}
+		if (titem == NULL)
+		    break;
+		detach(pack, titem);
+		inpack--;
+		put_contents(obj, titem);
+	    
+	    when '3':
+		titem = get_item(obj->contents,"take out",ALL);
+		if (titem == NULL)
+		    break;
+		take_contents(obj, titem);
+		
+	    when '4': 
+		switch (obj->o_which) {
+		case MM_BEAKER: 
+		    titem = get_item(obj->contents,"quaff",ALL);
+		    if (titem == NULL)
+			break;
+		    obj->o_ac--;
+		    detach(obj->contents, titem);
+		    quaff((OBJPTR(titem))->o_which, 
+			  (OBJPTR(titem))->o_flags & (ISCURSED | ISBLESSED),
+			  TRUE);
+		    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);
+		    if (titem == NULL)
+			break;
+		    obj->o_ac--;
+		    detach(obj->contents, titem);
+		    read_scroll((OBJPTR(titem))->o_which, 
+			        (OBJPTR(titem))->o_flags & (ISCURSED|ISBLESSED),
+				TRUE);
+		    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 (hw,' ');
+		clearok(cw, TRUE);
+		touchwin(cw);
+	}
+    }
+}
+
+do_panic()
+{
+    register int x,y;
+    register struct linked_list *mon;
+    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);
+		    if (!on(*th, ISUNDEAD) && !save(VS_MAGIC, th, 0)) {
+			turn_on(*th, ISFLEE);
+			turn_on(*th, WASTURNED);
+
+			/* 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);
+		    }
+		    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:
+	    switch (obj->o_ac) {
+	    case C_MAGICIAN:	strcpy(buf1, " [magic user]");
+	    when C_FIGHTER:	strcpy(buf1, " [fighter]");
+	    when C_CLERIC:	strcpy(buf1, " [cleric]");
+	    when C_THIEF:	strcpy(buf1, " [thief]");
+	    }
+    }
+    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();
+	    }
+    }
+}
+
+use_mm(which)
+int which;
+{
+    register struct object *obj = NULL;
+    register struct linked_list *item = NULL;
+    bool cursed, blessed, is_mm;
+    char buf[LINELEN];
+
+    cursed = FALSE;
+    is_mm = FALSE;
+
+    if (which < 0) {	/* A real miscellaneous magic item  */
+	is_mm = TRUE;
+	item = get_item(pack, "use", USEABLE);
+	/*
+	 * Make certain that it is a micellaneous magic item
+	 */
+	if (item == NULL)
+	    return;
+
+	obj = OBJPTR(item);
+	cursed = (obj->o_flags & ISCURSED) != 0;
+	blessed = (obj->o_flags & ISBLESSED) != 0;
+	which = obj->o_which;
+    }
+
+    if (obj->o_type == RELIC) {		/* An artifact */
+	is_mm = FALSE;
+	switch (obj->o_which) {
+	    case EMORI_CLOAK:
+		use_emori();
+	    when BRIAN_MANDOLIN:
+		/* Put monsters around us to sleep */
+		read_scroll(S_HOLD, 0, FALSE);
+	    when GERYON_HORN:
+		/* Chase close monsters away */
+		msg("The horn blasts a shrill tone.");
+		do_panic();
+	    when HEIL_ANKH:
+	    case YENDOR_AMULET:
+		/* Nothing happens by this mode */
+		msg("Nothing happens.");
+	}
+    }
+    else switch (which) {		/* Miscellaneous Magic */
+	/*
+	 * the jug of alchemy manufactures potions when you drink
+	 * the potion it will make another after a while
+	 */
+	case MM_JUG:
+	    if (obj->o_ac == JUG_EMPTY) {
+		msg("The jug is empty");
+		break;
+	    }
+	    quaff (obj->o_ac, NULL, FALSE);
+	    obj->o_ac = JUG_EMPTY;
+	    fuse (alchemy, obj, ALCHEMYTIME, AFTER);
+	    if (!(obj->o_flags & ISKNOW))
+	        whatis(item);
+
+	/*
+	 * the beaker of plentiful potions is used to hold potions
+	 * the book of infinite spells is used to hold scrolls
+	 */
+	when MM_BEAKER:
+	case MM_BOOK:
+	    do_bag(item);
+
+	/*
+	 * the chime of opening opens up secret doors
+	 */
+	when MM_OPEN:
+	{
+	    register struct linked_list *exit;
+	    register struct room *rp;
+	    register coord *cp;
+
+	    if (obj->o_charges <= 0) {
+		msg("The chime is cracked!");
+		break;
+	    }
+	    obj->o_charges--;
+	    msg("chime... chime... hime... ime... me... e...");
+	    if ((rp = roomin(&hero)) == NULL) {
+		search(FALSE, TRUE); /* Non-failing search for door */
+		break;
+	    }
+	    for (exit = rp->r_exit; exit != NULL; exit = next(exit)) {
+		cp = DOORPTR(exit);
+		if (winat(cp->y, cp->x) == SECRETDOOR) {
+		    mvaddch (cp->y, cp->x, DOOR);
+		    if (cansee (cp->y, cp->x))
+			mvwaddch(cw, cp->y, cp->x, DOOR);
+		}
+	    }
+	}
+
+	/*
+	 * the chime of hunger just makes the hero hungry
+	 */
+	when MM_HUNGER:
+	    if (obj->o_charges <= 0) {
+		msg("The chime is cracked!");
+		break;
+	    }
+	    obj->o_charges--;
+	    food_left = MORETIME + 5;
+	    msg(terse ? "Getting hungry" : "You are starting to get hungry");
+	    hungry_state = F_HUNGRY;
+	    aggravate();
+
+	/*
+	 * the drums of panic make all creatures within two squares run
+	 * from the hero in panic unless they save or they are mindless
+	 * undead
+	 */
+	when MM_DRUMS:
+	    if (obj->o_charges <= 0) {
+		msg("The drum is broken!");
+		break;
+	    }
+	    obj->o_charges--;
+	/*
+	 * dust of disappearance makes the player invisible for a while
+	 */
+	when MM_DISAPPEAR:
+	    m_know[MM_DISAPPEAR] = TRUE;
+	    if (obj->o_charges <= 0) {
+		msg("No more dust!");
+		break;
+	    }
+	    obj->o_charges--;
+	    msg("aaAAACHOOOooo. Cough. Cough. Sneeze. Sneeze.");
+	    if (!find_slot(dust_appear)) {
+		turn_on(player, ISINVIS);
+		fuse(dust_appear, 0, DUSTTIME, AFTER);
+		PLAYER = IPLAYER;
+		light(&hero);
+	    }
+	    else lengthen(dust_appear, DUSTTIME);
+
+	/*
+	 * dust of choking and sneezing can kill the hero if he misses
+	 * the save
+	 */
+	when MM_CHOKE:
+	    m_know[MM_CHOKE] = TRUE;
+	    if (obj->o_charges <= 0) {
+		msg("No more dust!");
+		break;
+	    }
+	    obj->o_charges--;
+	    msg("aaAAACHOOOooo. Cough. Cough. Sneeze. Sneeze.");
+	    if (!save(VS_POISON, &player, 0)) {
+		msg ("You choke to death!!! --More--");
+		pstats.s_hpt = -1; /* in case he hangs up the phone */
+		wait_for(cw,' ');
+		death(D_CHOKE);
+	    }
+	    else {
+		msg("You begin to cough and choke uncontrollably");
+		if (find_slot(unchoke))
+		    lengthen(unchoke, DUSTTIME);
+		else
+		    fuse(unchoke, 0, DUSTTIME, AFTER);
+		turn_on(player, ISHUH);
+		turn_on(player, ISBLIND);
+		light(&hero);
+	    }
+		
+	when MM_KEOGHTOM:
+	    /*
+	     * this is a very powerful healing ointment
+	     * but it takes a while to put on...
+	     */
+	    if (obj->o_charges <= 0) {
+		msg("The jar is empty!");
+		break;
+	    }
+	    obj->o_charges--;
+	    waste_time();
+	    if (on(player, HASDISEASE)) {
+		extinguish(cure_disease);
+		cure_disease();
+		msg(terse ? "You feel yourself improving."
+			  : "You begin to feel yourself improving again.");
+	    }
+	    if (on(player, HASINFEST)) {
+		turn_off(player, HASINFEST);
+		infest_dam = 0;
+		msg(terse ? "You feel yourself improving."
+			  : "You begin to feel yourself improving again.");
+	    }
+	    if (on(player, DOROT)) {
+		msg("You feel your skin returning to normal.");
+		turn_off(player, DOROT);
+	    }
+	    pstats.s_hpt += roll(pstats.s_lvl, 6);
+	    if (pstats.s_hpt > max_stats.s_hpt)
+		pstats.s_hpt = max_stats.s_hpt;
+	    sight();
+	    msg("You begin to feel much better.");
+		
+	/*
+	 * The book has a character class associated with it.
+	 * if your class matches that of the book, it will raise your 
+	 * level by one. If your class does not match the one of the book, 
+	 * it change your class to that of book.
+	 * Note that it takes a while to read.
+	 */
+	when MM_SKILLS:
+	    detach (pack, item);
+	    inpack--;
+	    waste_time();
+	    waste_time();
+	    waste_time();
+	    waste_time();
+	    waste_time();
+	    if (obj->o_ac == player.t_ctype) {
+		msg("You feel more skillful");
+		raise_level(TRUE);