/* * 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 #include #include #include "rogue.h" /* * See if a monster has some magic it can use. Use it and return TRUE if so. */ bool m_use_item(struct thing *monster, coord *monst_pos, coord *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 * bag: the holder of the items * item: the item to put inside */ void put_contents(struct object *bag, struct linked_list *item) { 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 * bag: the holder of the items */ void take_contents(struct object *bag, 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); } void do_bag(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); } } } void do_panic(void) { 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(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; } void use_emori(void) { 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(); } } } void use_mm(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, 0, 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); } 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 (obj->o_ac == C_THIEF && cur_armor != NULL && cur_armor->o_which != LEATHER && cur_armor->o_which != STUDDED_LEATHER ) cur_armor->o_which = STUDDED_LEATHER; /* * 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 && cur_weapon != NULL && cur_weapon->o_type == WEAPON && (cur_weapon->o_which== BASWORD || cur_weapon->o_which== TWOSWORD )) cur_weapon->o_which = SWORD; /* * if he was a thief then take out the trap_look() daemon */ if (player.t_ctype == C_THIEF) kill_daemon(trap_look); /* * if he becomes a thief then add the trap_look() daemon */ if (obj->o_ac == C_THIEF) start_daemon(trap_look, 0, AFTER); char_type = player.t_ctype = obj->o_ac; save = pstats.s_hpt; max_stats.s_hpt = pstats.s_hpt = 0; max_stats.s_lvl = pstats.s_lvl = 0; max_stats.s_exp = pstats.s_exp -= pstats.s_exp/10; check_level(TRUE); if (pstats.s_hpt > save) /* don't add to current hits */ pstats.s_hpt = save; } otherwise: msg("What a strange magic item you have!"); } status(FALSE); if (is_mm && m_know[which] && m_guess[which]) { free(m_guess[which]); m_guess[which] = NULL; } else if (is_mm && !m_know[which] && askme && (obj->o_flags & ISKNOW) == 0 && m_guess[which] == NULL) { msg(terse ? "Call it: " : "What do you want to call it? "); if (get_str(buf, msgw) == NORM) { m_guess[which] = new((unsigned int) strlen(buf) + 1); strcpy(m_guess[which], buf); } } if (item != NULL && which == MM_SKILLS) o_discard(item); updpack(TRUE); }