Mercurial > hg > early-roguelike
diff xrogue/move.c @ 133:e6179860cb76
Import XRogue 8.0 from the Roguelike Restoration Project (r1490)
author | John "Elwin" Edwards |
---|---|
date | Tue, 21 Apr 2015 08:55:20 -0400 |
parents | |
children | a0a57cf42810 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xrogue/move.c Tue Apr 21 08:55:20 2015 -0400 @@ -0,0 +1,1910 @@ +/* + move.c - Hero movement commands + + XRogue: Expeditions into the Dungeons of Doom + Copyright (C) 1991 Robert Pietkivitch + All rights reserved. + + Based on "Advanced Rogue" + Copyright (C) 1984, 1985 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" + +/* + * Used to hold the new hero position + */ + +coord move_nh; + +static char Moves[3][3] = { + { 'y', 'k', 'u' }, + { 'h', '.', 'l' }, + { 'b', 'j', 'n' } +}; + +/* + * be_trapped: + * The guy stepped on a trap.... Make him pay. + */ + +be_trapped(th, tc) +register struct thing *th; +register coord *tc; +{ + register struct trap *tp; + register char ch, *mname = NULL; + register bool is_player = (th == &player), + can_see; + register struct linked_list *mitem = NULL; + register struct thing *mp; + + + /* Can the player see the creature? */ + can_see = cansee(tc->y, tc->x); + can_see &= (is_player || !invisible(th)); + + tp = trap_at(tc->y, tc->x); + /* + * if he's wearing boots of elvenkind, he won't set off the trap + * unless its a magic pool (they're not really traps) + */ + if (is_player && + cur_misc[WEAR_BOOTS] != NULL && + cur_misc[WEAR_BOOTS]->o_which == MM_ELF_BOOTS && + tp->tr_type != POOL) + return '\0'; + + /* + * if the creature is flying then it won't set off the trap + */ + if (on(*th, ISFLY)) + return '\0'; + + tp->tr_flags |= ISFOUND; + + if (!is_player) { + mitem = find_mons(th->t_pos.y, th->t_pos.x); + mname = monster_name(th); + } + else { + count = running = FALSE; + mvwaddch(cw, tp->tr_pos.y, tp->tr_pos.x, tp->tr_type); + } + switch (ch = tp->tr_type) { + case TRAPDOOR: + if (is_player) { + level++; + pstats.s_hpt -= roll(1, 10); + msg("You fell through a trap! "); + if (pstats.s_hpt < 1) { + pstats.s_hpt = -1; + death(D_FALL); + } + wclear(cw); + wclear(mw); + new_level(NORMLEV); + } + else { + if (can_see) msg("%s fell into a trap!", prname(mname, TRUE)); + + /* + * See if the fall killed the monster + * don't let a UNIQUE die since it might have an artifact + * that we need + */ + if (off(*th,ISUNIQUE) && (th->t_stats.s_hpt-=roll(1,10)) <= 0){ + killed(mitem, FALSE, FALSE, FALSE); + } + else { /* Just move monster to next level */ + check_residue(th); + + /* Erase the monster from the old position */ + if (isalpha(mvwinch(cw, th->t_pos.y, th->t_pos.x))) + mvwaddch(cw, th->t_pos.y, th->t_pos.x, th->t_oldch); + mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' '); + + /* let him summon on next lvl */ + if (on (*th, HASSUMMONED)) { + turn_off(*th, HASSUMMONED); + turn_on(*th, CANSUMMON); + } + turn_on(*th,ISELSEWHERE); + detach(mlist, mitem); + attach(tlist, mitem); /* remember him next level */ + + /* Make sure that no one is still chasing us */ + for (mitem = mlist; mitem != NULL; mitem = next(mitem)) { + mp = THINGPTR(mitem); + if (mp->t_dest == &th->t_pos) { + mp->t_dest = &hero; + mp->t_wasshot = FALSE; + turn_off(*mp, ISFLEE); /* Don't run away! */ + } + } + + /* Make sure we were not chasing a monster here */ + th->t_dest = &hero; + if (on(*th, ISFRIENDLY)) turn_off(*th, ISFLEE); + } + } + /* worm hole trap to OUTSIDE */ + when WORMHOLE: + if (is_player) { + prev_max = 1000; /* flag used in n_level.c */ + level++; + msg("You suddenly find yourself in strange surroundings! "); + pstats.s_hpt -= roll(1, 10); + if (pstats.s_hpt < 1) { + pstats.s_hpt = -1; + death(D_FALL); + } + new_level(OUTSIDE); + return(ch); + } + else { + if (can_see) msg("%s fell into the worm hole! ", prname(mname, TRUE)); + + /* + * See if the fall killed the monster + * don't let a UNIQUE die since it might have an artifact + * that we need + */ + if (off(*th,ISUNIQUE) && (th->t_stats.s_hpt-=roll(1,10)) <= 0){ + killed(mitem, FALSE, FALSE, FALSE); + } + else { /* Just move monster to next level */ + check_residue(th); + + /* Erase the monster from the old position */ + if (isalpha(mvwinch(cw, th->t_pos.y, th->t_pos.x))) + mvwaddch(cw, th->t_pos.y, th->t_pos.x, th->t_oldch); + mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' '); + + /* let him summon on next lvl */ + if (on (*th, HASSUMMONED)) { + turn_off(*th, HASSUMMONED); + turn_on(*th, CANSUMMON); + } + + turn_on(*th,ISELSEWHERE); + detach(mlist, mitem); + attach(tlist, mitem); /* remember him next level */ + + /* Make sure that no one is still chasing us */ + for (mitem = mlist; mitem != NULL; mitem = next(mitem)) { + mp = THINGPTR(mitem); + if (mp->t_dest == &th->t_pos) { + mp->t_dest = &hero; + mp->t_wasshot = FALSE; + turn_off(*mp, ISFLEE); /* Don't run away! */ + } + } + + /* Make sure we were not chasing a monster here */ + th->t_dest = &hero; + if (on(*th, ISFRIENDLY)) turn_off(*th, ISFLEE); + } + } + when BEARTRAP: + if (is_stealth(th)) { + if (is_player) msg("You pass a bear trap."); + else if (can_see) msg("%s passes a bear trap.", + prname(mname, TRUE)); + } + else { + th->t_no_move += movement(&player) * BEARTIME; + th->t_action = A_FREEZE; + if (is_player) msg("You are caught in a bear trap."); + else if (can_see) msg("%s is caught in a bear trap.", + prname(mname, TRUE)); + } + when SLEEPTRAP: + if (is_player) { + if (!ISWEARING(R_ALERT)) { + msg("A strange white mist envelops you. You fall asleep. "); + player.t_no_move += movement(&player) * SLEEPTIME; + player.t_action = A_FREEZE; + } + else { + msg("The white mist invigorates you. "); + } + } + else { + if (can_see) + msg("A strange white mist envelops %s. ", + prname(mname, FALSE)); + if (on(*th, ISUNDEAD)) { + if (can_see) + msg("The mist doesn't seem to affect %s.", + prname(mname, FALSE)); + } + else { + th->t_no_move += movement(th) * SLEEPTIME; + th->t_action = A_FREEZE; + } + } + when ARROWTRAP: + if (swing(th->t_ctype, th->t_stats.s_lvl-1, th->t_stats.s_arm, 1)) + { + if (is_player) { + msg("Oh no! An arrow shot you."); + if ((pstats.s_hpt -= roll(1, 8)) < 1) { + pstats.s_hpt = -1; + msg("The arrow killed you. --More--"); + wait_for(' '); + death(D_ARROW); + } + } + else { + if (can_see) + msg("An arrow shot %s.", prname(mname, FALSE)); + if ((th->t_stats.s_hpt -= roll(1, 8)) < 1) { + if (can_see) + msg("The arrow killed %s.", prname(mname, FALSE)); + killed(mitem, FALSE, FALSE, TRUE); + } + } + } + else + { + register struct linked_list *item; + register struct object *arrow; + + if (is_player) msg("An arrow shoots past you."); + else if (can_see) + msg("An arrow shoots by %s.", prname(mname, FALSE)); + item = new_item(sizeof *arrow); + arrow = OBJPTR(item); + arrow->o_type = WEAPON; + arrow->contents = NULL; + arrow->o_which = ARROW; + arrow->o_hplus = rnd(7) - 1; + arrow->o_dplus = rnd(7) - 1; + init_weapon(arrow, ARROW); + arrow->o_count = 1; + arrow->o_pos = *tc; + arrow->o_mark[0] = '\0'; + fall(item, FALSE); + } + when TELTRAP: + if (is_player) teleport(); + else { + register int rm; + struct room *old_room; /* old room of monster */ + + /* + * Erase the monster from the old position + */ + if (isalpha(mvwinch(cw, th->t_pos.y, th->t_pos.x))) + mvwaddch(cw, th->t_pos.y, th->t_pos.x, th->t_oldch); + mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' '); + /* + * check to see if room should go dark + */ + if (on(*th, HASFIRE)) { + old_room=roomin(&th->t_pos); + if (old_room != NULL) { + register struct linked_list *fire_item; + + for (fire_item = old_room->r_fires; fire_item != NULL; + fire_item = next(fire_item)) { + if (THINGPTR(fire_item) == th) { + detach(old_room->r_fires, fire_item); + destroy_item(fire_item); + + if (old_room->r_fires == NULL) { + old_room->r_flags &= ~HASFIRE; + if (can_see) light(&hero); + } + } + } + } + } + + /* Get a new position */ + do { + rm = rnd_room(); + rnd_pos(&rooms[rm], &th->t_pos); + } until(winat(th->t_pos.y, th->t_pos.x) == FLOOR); + + /* Put it there */ + mvwaddch(mw, th->t_pos.y, th->t_pos.x, th->t_type); + th->t_oldch = mvwinch(cw, th->t_pos.y, th->t_pos.x); + /* + * check to see if room that creature appears in should + * light up + */ + if (on(*th, HASFIRE)) { + register struct linked_list *fire_item; + + fire_item = creat_item(); + ldata(fire_item) = (char *) th; + attach(rooms[rm].r_fires, fire_item); + + rooms[rm].r_flags |= HASFIRE; + if(cansee(th->t_pos.y, th->t_pos.x) && + next(rooms[rm].r_fires) == NULL) + light(&hero); + } + if (can_see) + msg("%s seems to have disappeared!", prname(mname, TRUE)); + } + when DARTTRAP: + if (swing(th->t_ctype, th->t_stats.s_lvl+1, th->t_stats.s_arm, 1)) { + if (is_player) { + msg("A small dart just hit you. "); + if ((pstats.s_hpt -= roll(1, 8)) < 1) { + pstats.s_hpt = -1; + msg("The dart killed you."); + wait_for(' '); + death(D_DART); + } + + /* Now the poison */ + if (!save(VS_POISON, &player, 0)) { + /* 75% chance it will do point damage - else strength */ + if (rnd(100) < 75) { + pstats.s_hpt /= 2; + if (pstats.s_hpt < 1) { + pstats.s_hpt = -1; + death(D_POISON); + } + } + else if (!ISWEARING(R_SUSABILITY)) + chg_str(-1); + } + } + else { + if (can_see) + msg("A small dart stabs the %s. ", + prname(mname, FALSE)); + if ((th->t_stats.s_hpt -= roll(1,8)) < 1) { + if (can_see) + msg("The dart killed %s.", prname(mname, FALSE)); + killed(mitem, FALSE, FALSE, TRUE); + } + if (!save(VS_POISON, th, 0)) { + th->t_stats.s_hpt /= 2 + level; + if (th->t_stats.s_hpt < 1) { + if (can_see) + msg("The dart killed %s.", prname(mname,FALSE)); + killed(mitem, FALSE, FALSE, TRUE); + } + } + } + } + else { + if (is_player) + msg("A small dart whizzes by your ear and vanishes."); + else if (can_see) + msg("A small dart whizzes by %s's ear and vanishes.", + prname(mname, FALSE)); + } + when POOL: { + register int i; + + i = rnd(100); + if (is_player) { + if ((tp->tr_flags & ISGONE)) { + if (i < 56) { + teleport(); /* teleport away */ + pool_teleport = TRUE; + } + else if((i < 72) && level > 4) { + level -= rnd(4) + 1; + cur_max = level; + new_level(NORMLEV); + pool_teleport = TRUE; + msg("You here a faint groan from below."); + } + else if(i < 85) { + level += rnd(4) + 1; + new_level(NORMLEV); + pool_teleport = TRUE; + msg("You find yourself in strange surroundings."); + } + else if(i > 96) { + msg("Oh no!!! You drown in the pool!!! --More--"); + wait_for(' '); + pstats.s_hpt = -1; + death(D_DROWN); + } + else { + new_level(NORMLEV); + pool_teleport = TRUE; + msg("You are whisked away to another region."); + } + } + } + else { + if (i < 60) { + if (can_see) { + /* Drowns */ + if (i < 50) + msg("%s drowned in the pool!", prname(mname, TRUE)); + + /* Teleported to another level */ + else msg("%s disappeared!", prname(mname, TRUE)); + } + killed(mitem, FALSE, FALSE, TRUE); + } + } + } + when MAZETRAP: + if (is_player) { + pstats.s_hpt -= roll(1, 10); + level++; + if (pstats.s_hpt < 1) { + pstats.s_hpt = -1; + death(D_FALL); + } + wclear(cw); + wclear(mw); + new_level(MAZELEV); + msg("You are surrounded by twisty passages! "); + } + else { + if (can_see) msg("%s fell into a maze trap!", prname(mname, TRUE)); + if (on(*th, ISUNIQUE)) { + check_residue(th); + + /* Erase the monster from the old position */ + if (isalpha(mvwinch(cw, th->t_pos.y, th->t_pos.x))) + mvwaddch(cw, th->t_pos.y, th->t_pos.x, th->t_oldch); + mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' '); + + /* let him summon on next lvl */ + if (on (*th, HASSUMMONED)) { + turn_off(*th, HASSUMMONED); + turn_on(*th, CANSUMMON); + } + turn_on(*th,ISELSEWHERE); + detach(mlist, mitem); + attach(tlist, mitem); /* remember him next level */ + + /* Make sure that no one is still chasing us */ + for (mitem = mlist; mitem != NULL; mitem = next(mitem)) { + mp = THINGPTR(mitem); + if (mp->t_dest == &th->t_pos) { + mp->t_dest = &hero; + mp->t_wasshot = FALSE; + turn_off(*mp, ISFLEE); /* Don't run away! */ + } + } + + /* Make sure we were not chasing a monster here */ + th->t_dest = &hero; + if (on(*th, ISFRIENDLY)) turn_off(*th, ISFLEE); + } + else + killed(mitem, FALSE, FALSE, FALSE); + } + } + + /* Move the cursor back onto the hero */ + wmove(cw, hero.y, hero.x); + + flushinp(); + return(ch); +} + +/* + * blue_light: + * magically light up a room (or level or make it dark) + */ + +bool +blue_light(blessed, cursed) +bool blessed, cursed; +{ + register struct room *rp; + bool ret_val=FALSE; /* Whether or not affect is known */ + + rp = roomin(&hero); /* What room is hero in? */ + + /* Darken the room if the magic is cursed */ + if (cursed) { + if ((rp == NULL) || !lit_room(rp)) msg(nothing); + else { + rp->r_flags |= ISDARK; + if (!lit_room(rp) && (levtype != OUTSIDE || !daytime) && + !ISWEARING(R_LIGHT)) + msg("The %s suddenly goes dark.", + levtype == OUTSIDE ? "area" : "room"); + else msg(nothing); + ret_val = TRUE; + } + } + else { + ret_val = TRUE; + if (rp && !lit_room(rp) && + (levtype != OUTSIDE || !daytime)) { + addmsg("The %s is lit", levtype == OUTSIDE ? "area" : "room"); + addmsg(" by a %s blue light.", blessed ? "bright" : "shimmering"); + endmsg(); + } + else if (winat(hero.y, hero.x) == PASSAGE) + msg("The corridor glows %sand then fades", + blessed ? "brightly " : ""); + else { + ret_val = FALSE; + msg(nothing); + } + if (blessed) { + register int i; /* Index through rooms */ + + for (i=0; i<MAXROOMS; i++) + rooms[i].r_flags &= ~ISDARK; + } + else if (rp) rp->r_flags &= ~ISDARK; + } + + /* + * Light the room and put the player back up + */ + light(&hero); + mvwaddch(cw, hero.y, hero.x, PLAYER); + return(ret_val); +} + +/* + * corr_move: + * Check to see that a move is legal. If so, return correct character. + * If not, if player came from a legal place, then try to turn him. + */ + +corr_move(dy, dx) +int dy, dx; +{ + int legal=0; /* Number of legal alternatives */ + register int y, x, /* Indexes though possible positions */ + locy = 0, locx = 0; /* Hold delta of chosen location */ + + /* New position */ + move_nh.y = hero.y + dy; + move_nh.x = hero.x + dx; + + /* If it is a legal move, just return */ + if (move_nh.x >= 0 && move_nh.x < cols && move_nh.y > 0 && move_nh.y < lines - 2) { + + switch (winat(move_nh.y, move_nh.x)) { + case WALL: + case VERTWALL: + case HORZWALL: + break; + default: + if (diag_ok(&hero, &move_nh, &player)) + return; + } + } + + /* Check legal places surrounding the player -- ignore previous position */ + for (y = hero.y - 1; y <= hero.y + 1; y++) { + if (y < 1 || y > lines - 3) + continue; + for (x = hero.x - 1; x <= hero.x + 1; x++) { + /* Ignore borders of the screen */ + if (x < 0 || x > cols - 1) + continue; + + /* + * Ignore where we came from, where we are, and where we couldn't go + */ + if ((x == hero.x - dx && y == hero.y - dy) || + (x == hero.x + dx && y == hero.y + dy) || + (x == hero.x && y == hero.y)) + continue; + + switch (winat(y, x)) { + case WALL: + case VERTWALL: + case HORZWALL: + break; + default: + move_nh.y = y; + move_nh.x = x; + if (diag_ok(&hero, &move_nh, &player)) { + legal++; + locy = y - (hero.y - 1); + locx = x - (hero.x - 1); + } + } + } + } + + /* If we have 2 or more legal moves, make no change */ + if (legal != 1) { + return; + } + + runch = Moves[locy][locx]; + + /* + * For mazes, pretend like it is the beginning of a new run at each turn + * in order to get the lighting correct. + */ + if (levtype == MAZELEV) firstmove = TRUE; + return; +} + +/* + * dip_it: + * Dip an object into a magic pool + */ + +dip_it() +{ + reg struct linked_list *what; + reg struct object *ob; + reg struct trap *tp; + reg int wh, i; + + tp = trap_at(hero.y,hero.x); + if (tp == NULL || tp->tr_type != POOL) { + msg("I see no shimmering pool here"); + return; + } + if (tp->tr_flags & ISGONE) { + msg("This shimmering pool appears to have been used once already."); + return; + } + + /* It takes 3 movement periods to dip something */ + if (player.t_action != C_DIP) { + if ((what = get_item(pack, "dip", ALL, FALSE, FALSE)) == NULL) { + msg(""); + after = FALSE; + return; + } + + ob = OBJPTR(what); + if (ob == cur_armor || + ob == cur_misc[WEAR_BOOTS] || + ob == cur_misc[WEAR_JEWEL] || + ob == cur_misc[WEAR_GAUNTLET] || + ob == cur_misc[WEAR_CLOAK] || + ob == cur_misc[WEAR_BRACERS] || + ob == cur_misc[WEAR_NECKLACE] || + ob == cur_ring[LEFT_1] || ob == cur_ring[LEFT_2] || + ob == cur_ring[LEFT_3] || ob == cur_ring[LEFT_4] || + ob == cur_ring[RIGHT_1] || ob == cur_ring[RIGHT_2] || + ob == cur_ring[RIGHT_3] || ob == cur_ring[RIGHT_4]) { + mpos = 0; + msg("You'll have to take it off first."); + return; + } + + player.t_using = what; /* Remember what it is */ + player.t_action = C_DIP; /* We are dipping */ + player.t_no_move = 3 * movement(&player); + return; + } + + /* We have waited our time, let's dip it */ + what = player.t_using; + player.t_using = NULL; + player.t_action = A_NIL; + + ob = OBJPTR(what); + + tp->tr_flags |= ISGONE; + if (ob != NULL) { + wh = ob->o_which; + ob->o_flags |= ISKNOW; + i = rnd(100); + if (ob->o_group != 0) + ob->o_group = newgrp(); /* change the group */ + switch(ob->o_type) { + case WEAPON: + if(i < 60) { /* enchant weapon here */ + if ((ob->o_flags & ISCURSED) == 0) { + ob->o_hplus += 1; + ob->o_dplus += 1; + } + else { /* weapon was prev cursed here */ + ob->o_hplus = rnd(2); + ob->o_dplus = rnd(2); + } + ob->o_flags &= ~ISCURSED; + msg("The %s glows blue for a moment.",weaps[wh].w_name); + } + else if(i < 75) { /* curse weapon here */ + if ((ob->o_flags & ISCURSED) == 0) { + ob->o_hplus = -(rnd(2)+1); + ob->o_dplus = -(rnd(2)+1); + } + else { /* if already cursed */ + ob->o_hplus--; + ob->o_dplus--; + } + ob->o_flags |= ISCURSED; + msg("The %s glows red for a moment.",weaps[wh].w_name); + } + else + msg(nothing); + when ARMOR: + if (i < 60) { /* enchant armor */ + if((ob->o_flags & ISCURSED) == 0) + ob->o_ac -= rnd(2) + 1; + else + ob->o_ac = -rnd(3)+ armors[wh].a_class; + ob->o_flags &= ~ISCURSED; + msg("The %s glows blue for a moment",armors[wh].a_name); + } + else if(i < 75){ /* curse armor */ + if ((ob->o_flags & ISCURSED) == 0) + ob->o_ac = rnd(3)+ armors[wh].a_class; + else + ob->o_ac += rnd(2) + 1; + ob->o_flags |= ISCURSED; + msg("The %s glows red for a moment.",armors[wh].a_name); + } + else + msg(nothing); + when STICK: { + int j; + j = rnd(14) + 1; + if(i < 60) { /* add charges */ + ob->o_charges += j; + ws_know[wh] = TRUE; + if (ob->o_flags & ISCURSED) + ob->o_flags &= ~ISCURSED; + msg("The %s %s glows blue for a moment.", + ws_made[wh],ws_type[wh]); + } + else if(i < 75) { /* remove charges */ + if ((ob->o_charges -= i) < 0) + ob->o_charges = 0; + ws_know[wh] = TRUE; + if (ob->o_flags & ISBLESSED) + ob->o_flags &= ~ISBLESSED; + else + ob->o_flags |= ISCURSED; + msg("The %s %s glows red for a moment.", + ws_made[wh],ws_type[wh]); + } + else + msg(nothing); + } + when SCROLL: + s_know[wh] = TRUE; + msg("The '%s' scroll unfurls.",s_names[wh]); + when POTION: + p_know[wh] = TRUE; + msg("The %s potion bubbles for a moment.. ",p_colors[wh]); + when RING: + if(i < 60) { /* enchant ring */ + if ((ob->o_flags & ISCURSED) == 0) + ob->o_ac += rnd(2) + 1; + else + ob->o_ac = rnd(2) + 1; + ob->o_flags &= ~ISCURSED; + } + else if(i < 75) { /* curse ring */ + if ((ob->o_flags & ISCURSED) == 0) + ob->o_ac = -(rnd(2) + 1); + else + ob->o_ac -= (rnd(2) + 1); + ob->o_flags |= ISCURSED; + } + r_know[wh] = TRUE; + msg("The %s ring vibrates for a moment.",r_stones[wh]); + when MM: + m_know[wh] = TRUE; + switch (ob->o_which) { + case MM_BRACERS: + case MM_PROTECT: + if(i < 60) { /* enchant item */ + if ((ob->o_flags & ISCURSED) == 0) + ob->o_ac += rnd(2) + 1; + else + ob->o_ac = rnd(2) + 1; + ob->o_flags &= ~ISCURSED; + } + else if(i < 75) { /* curse item */ + if ((ob->o_flags & ISCURSED) == 0) + ob->o_ac = -(rnd(2) + 1); + else + ob->o_ac -= (rnd(2) + 1); + ob->o_flags |= ISCURSED; + } + msg("The item vibrates for a moment."); + when MM_CHOKE: + case MM_DISAPPEAR: + ob->o_ac = 0; + msg ("The dust dissolves in the pool!"); + } + otherwise: + msg("The pool bubbles up for a moment.. "); + } + updpack(FALSE, &player); + } + else + msg(nothing); +} + +/* + * do_move: + * Check to see that a move is legal. If it is handle the + * consequences (fighting, picking up, etc.) + */ + +do_move(dy, dx) +int dy, dx; +{ + register struct room *rp, *orp; + register unsigned char ch; + struct linked_list *item; + register struct thing *tp = NULL; + coord old_hero; + register int wasfirstmove, moved, num_hits; + bool changed=FALSE; /* Did we switch places with a friendly monster? */ + + wasfirstmove = firstmove; + firstmove = FALSE; + curprice = -1; /* if in trading post, we've moved off obj */ + + /* + * Do a confused move (maybe) + */ + if (player.t_action == A_NIL && + ((on(player, ISHUH) && rnd(100) < 80) || + (on(player, ISDANCE) && rnd(100) < 90) || + (ISWEARING(R_DELUSION) && rnd(100) < 70))) + { + /* Get a random move */ + move_nh = rndmove(&player); + dy = move_nh.y - hero.y; + dx = move_nh.x - hero.x; + } + else { + move_nh.y = hero.y + dy; + move_nh.x = hero.x + dx; + } + + /* + * Check if he tried to move off the screen or make an illegal + * diagonal move, and stop him if he did. + */ + if (move_nh.x < 0 || move_nh.x > cols-1 || move_nh.y < 1 || move_nh.y >= lines - 2 + || !diag_ok(&hero, &move_nh, &player)) + { + after = running = FALSE; + player.t_action = A_NIL; + return; + } + if (running && ce(hero, move_nh)) + after = running = FALSE; + ch = winat(move_nh.y, move_nh.x); + + /* Take care of hero trying to move close to something frightening */ + if (on(player, ISFLEE)) { + if (rnd(100) < 12) { + turn_off(player, ISFLEE); + msg("You regain your composure."); + } + else if (DISTANCE(move_nh.y, move_nh.x, player.t_dest->y, player.t_dest->x) < + DISTANCE(hero.y, hero.x, player.t_dest->y, player.t_dest->x)) { + running = FALSE; + msg("You are too terrified to move that way"); + player.t_action = A_NIL; + player.t_no_move = movement(&player); + return; + } + } + + /* If we want to move to a monster, see what it is */ + if (isalpha(ch)) { + item = find_mons(move_nh.y, move_nh.x); + if (item == NULL) { + debug("Cannot find monster in move."); + player.t_action = A_NIL; + return; + } + tp = THINGPTR(item); + } + + /* + * Take care of hero being held. If the player is being held, he + * can't move unless he is either attacking a non-friendly monster + * or attacking a friendly monster that can't move. + */ + if (on(player, ISHELD) && + (!isalpha(ch) || (on(*tp, ISFRIENDLY) && off(*tp, ISHELD)))) { + msg("You are being held."); + player.t_action = A_NIL; + return; + } + + /* See if we have to wait for our movement rate */ + if (player.t_action == A_NIL) { + after = FALSE; + firstmove = wasfirstmove; /* Remember if this is first move */ + player.t_no_move = movement(&player); + if (player.t_ctype == C_MONK) + player.t_no_move -= pstats.s_lvl/6; + if (on(player, ISFLY)) + player.t_no_move /= 2; /* If flying, speed him up */ + + if (player.t_no_move < 1) player.t_no_move = 1; + + /* Remember our action */ + player.t_action = Moves[dy+1][dx+1]; + return; + } + + /* Now let's forget the old move and just do it */ + player.t_action = A_NIL; + + /* If we're moving onto a friendly monster, let's change places. */ + if (isalpha(ch) && on(*tp, ISFRIENDLY) && off(*tp, ISHELD)) { + coord tpos, /* Where monster may have been going */ + current; /* Current hero position */ + int action; /* The monster's action */ + + current = hero; + tpos = tp->t_newpos; + action = tp->t_action; + + /* Disrupt whatever our friend was doing */ + tp->t_action = A_NIL; + + /* Tentatively move us to where he is */ + hero = tp->t_pos; + + /* See if we can move him to where we were */ + tp->t_newpos = current; + do_chase(tp); + + /* Did we succeed? */ + if (ce(tp->t_pos, current)) { + /* Reset our idea of what ch is */ + ch = winat(move_nh.y, move_nh.x); + + /* Let it be known that we made the switch */ + changed = TRUE; + old_hero = current; + + /* Make the monster think it didn't move */ + tp->t_oldpos = current; + tp->t_doorgoal.x = tp->t_doorgoal.y = -1; + + /* Let the player know something funny happened. */ + msg("What a sidestep!"); + } + else { + /* Restore things -- we couldn't move */ + hero = current; + tp->t_newpos = tpos; + tp->t_action = action; + } + } + + /* assume he's not in a wall */ + if (!isalpha(ch)) turn_off(player, ISINWALL); + + switch (ch) { + case VERTWALL: + case HORZWALL: + if (levtype == OUTSIDE) { + hero = move_nh; + new_level(OUTSIDE); + return; + } + case WALL: + case SECRETDOOR: + if (off(player, CANINWALL) || running) { + after = running = FALSE; + + /* Light if finishing run */ + if (levtype == MAZELEV && lit_room(&rooms[0])) + look(FALSE, TRUE); + + after = running = FALSE; + + return; + } + turn_on(player, ISINWALL); + break; + case POOL: + if (levtype == OUTSIDE) { + /* lake_check(&move_nh); */ /* not implemented yet */ + running = FALSE; + break; + } + case MAZETRAP: + if (levtype == OUTSIDE) { + running = FALSE; + break; + } + case TRAPDOOR: + case TELTRAP: + case BEARTRAP: + case SLEEPTRAP: + case ARROWTRAP: + case DARTTRAP: + case WORMHOLE: + ch = be_trapped(&player, &move_nh); + if (ch == TRAPDOOR || ch == TELTRAP || + pool_teleport || ch == MAZETRAP) { + pool_teleport = FALSE; + return; + } + break; + case GOLD: + case POTION: + case SCROLL: + case FOOD: + case WEAPON: + case ARMOR: + case RING: + case MM: + case RELIC: + case STICK: + running = FALSE; + take = ch; + break; + case DOOR: + case STAIRS: + case POST: + running = FALSE; + break; + default: + break; + } + + if (isalpha(ch)) { /* if its a monster then fight it */ + /* + * If we were running down a corridor and didn't start right + * next to the critter, don't do anything. + */ + if (running && wasfirstmove == FALSE && roomin(&hero) == NULL) { + struct linked_list *item; + + item = find_mons(move_nh.y, move_nh.x); + if (item != NULL && !invisible(THINGPTR(item))) { + after = running = FALSE; + return; + } + } + + /* We have to add time because we're attacking */ + player.t_no_move = FIGHTBASE; + player.t_no_move += weap_move(&player, cur_weapon); + if (on(player, ISHASTE)) + player.t_no_move /= 2; + else if (on(player, ISSLOW)) + player.t_no_move *= 2; + + /* We may attack faster if we're high enough level + * and the right class + */ + switch(player.t_ctype) { + case C_FIGHTER: num_hits = player.t_stats.s_lvl/25 + 1; + when C_PALADIN: num_hits = player.t_stats.s_lvl/35 + 1; + when C_RANGER: num_hits = player.t_stats.s_lvl/35 + 1; + when C_MONK: if(cur_weapon) num_hits = player.t_stats.s_lvl/40 + 1; + else num_hits = player.t_stats.s_lvl/30 + 1; + otherwise: num_hits = player.t_stats.s_lvl/60 + 1; + } + + /* + * The player has already moved the initial movement period. + * Let's add that in, do our division, and then subtract it + * out so that the total time is divided, not just the + * additional attack time. + */ + moved = movement(&player), + player.t_no_move += moved; + player.t_no_move /= num_hits; + player.t_no_move -= moved; + running = FALSE; + + /* Mark that we are attacking and save the attack coordinate */ + player.t_action = A_ATTACK; + player.t_newpos = move_nh; + runch = Moves[dy+1][dx+1]; /* Remember the direction */ + + if (player.t_no_move <= 0) after = FALSE; + return; + } + + /* + * if not fighting then move the hero + */ + if (changed == FALSE) { + old_hero = hero; /* Save hero's old position */ + hero = move_nh; /* Move the hero */ + } + rp = roomin(&hero); + orp = roomin(&old_hero); + + /* Unlight any possible cross-corridor */ + if (levtype == MAZELEV) { + register bool call_light = FALSE; + register unsigned char wall_check; + + if (wasfirstmove && lit_room(&rooms[0])) { + /* Are we moving out of a corridor? */ + switch (runch) { + case 'h': + case 'l': + if (old_hero.y + 1 < lines - 2) { + wall_check = winat(old_hero.y + 1, old_hero.x); + if (!isrock(wall_check)) call_light = TRUE; + } + if (old_hero.y - 1 > 0) { + wall_check = winat(old_hero.y - 1, old_hero.x); + if (!isrock(wall_check)) call_light = TRUE; + } + break; + case 'j': + case 'k': + if (old_hero.x + 1 < cols) { + wall_check = winat(old_hero.y, old_hero.x + 1); + if (!isrock(wall_check)) call_light = TRUE; + } + if (old_hero.x - 1 >= 0) { + wall_check = winat(old_hero.y, old_hero.x - 1); + if (!isrock(wall_check)) call_light = TRUE; + } + break; + default: + call_light = TRUE; + } + player.t_oldpos = old_hero; + if (call_light) light(&old_hero); + } + } + + else if (orp != NULL && rp == NULL) { /* Leaving a room -- darken it */ + orp->r_flags |= FORCEDARK; /* Fake darkness */ + light(&old_hero); + orp->r_flags &= ~FORCEDARK; /* Restore light state */ + } + else if (rp != NULL && orp == NULL){/* Entering a room */ + light(&hero); + if (rp->r_flags & ISTREAS) + wake_room(rp); + } + ch = winat(old_hero.y, old_hero.x); + wmove(cw, unc(old_hero)); + waddch(cw, ch); + wmove(cw, unc(hero)); + waddch(cw, PLAYER); +} + +/* + * do_run: + * Start the hero running + */ + +do_run(ch) +char ch; +{ + firstmove = TRUE; + running = TRUE; + after = FALSE; + runch = ch; +} + +/* + * getdelta: + * Takes a movement character (eg. h, j, k, l) and returns the + * y and x delta corresponding to it in the remaining arguments. + * Returns TRUE if it could find it, FALSE otherwise. + */ + +bool +getdelta(match, dy, dx) +char match; +int *dy, *dx; +{ + register int y, x; + + for (y = 0; y < 3; y++) + for (x = 0; x < 3; x++) + if (Moves[y][x] == match) { + *dy = y - 1; + *dx = x - 1; + return(TRUE); + } + + return(FALSE); +} + +/* + * isatrap: + * Returns TRUE if this character is some kind of trap + */ + +isatrap(ch) +reg char ch; +{ + switch(ch) { + case WORMHOLE: + case DARTTRAP: + case TELTRAP: + case TRAPDOOR: + case ARROWTRAP: + case SLEEPTRAP: + case BEARTRAP: return(TRUE); + case MAZETRAP: + case POOL: return(levtype != OUTSIDE); + default: return(FALSE); + } +} + +/* + * Called to illuminate a room. + * If it is dark, remove anything that might move. + */ + +light(cp) +coord *cp; +{ + register struct room *rp; + register int j, k, x, y; + register unsigned char ch, rch, sch; + register struct linked_list *item; + int jlow, jhigh, klow, khigh; /* Boundaries of lit area */ + + if ((rp = roomin(cp)) != NULL) { + /* + * is he wearing ring of illumination? + */ + if (&hero == cp && ISWEARING(R_LIGHT)) /* Must be hero's room */ + rp->r_flags &= ~ISDARK; + + /* If we are in a maze, don't look at the whole room (level) */ + if (levtype == MAZELEV) { + int see_radius; + + see_radius = 1; + + /* If we are looking at the hero in a rock, broaden our sights */ + if (&hero == cp || &player.t_oldpos == cp) { + ch = winat(hero.y, hero.x); + if (isrock(ch)) see_radius = 2; + ch = winat(player.t_oldpos.y, player.t_oldpos.x); + if (isrock(ch)) see_radius = 2; + } + + jlow = max(0, cp->y - see_radius - rp->r_pos.y); + jhigh = min(rp->r_max.y, cp->y + see_radius + 1 - rp->r_pos.y); + klow = max(0, cp->x - see_radius - rp->r_pos.x); + khigh = min(rp->r_max.x, cp->x + see_radius + 1 - rp->r_pos.x); + } + else { + jlow = klow = 0; + jhigh = rp->r_max.y; + khigh = rp->r_max.x; + } + for (j = 0; j < rp->r_max.y; j++) + { + for (k = 0; k < rp->r_max.x; k++) + { + bool see_here = 0, see_before = 0; + + /* Is this in the give area -- needed for maze */ + if ((j < jlow || j >= jhigh) && (k < klow || k >= khigh)) + continue; + + y = rp->r_pos.y + j; + x = rp->r_pos.x + k; + + /* + * If we are in a maze do not look at this area unless + * we can see it from where we are or where we last were + * (for erasing purposes). + */ + if (levtype == MAZELEV) { + /* If we can't see it from here, could we see it before? */ + if ((see_here = maze_view(y, x)) == FALSE) { + coord savhero; + + /* Could we see it from where we were? */ + savhero = hero; + hero = player.t_oldpos; + see_before = maze_view(y, x); + hero = savhero; + + if (!see_before) continue; + } + } + + ch = show(y, x); + wmove(cw, y, x); + /* + * Figure out how to display a secret door + */ + if (ch == SECRETDOOR) { + if (j == 0 || j == rp->r_max.y - 1) + ch = HORZWALL; + else + ch = VERTWALL; + } + /* For monsters, if they were previously not seen and + * now can be seen, or vice-versa, make sure that will + * happen. This is for dark rooms as opposed to invisibility. + * + * Call winat() in the test because ch will not reveal + * invisible monsters. + */ + if (isalpha(winat(y, x))) { + struct thing *tp; /* The monster */ + + item = wake_monster(y, x); + tp = THINGPTR(item); + + /* Previously not seen -- now can see it */ + if (tp->t_oldch == ' ' && cansee(tp->t_pos.y, tp->t_pos.x)) + tp->t_oldch = mvinch(y, x); + + /* Previously seen -- now can't see it */ + else if (!cansee(tp->t_pos.y, tp->t_pos.x) && + roomin(&tp->t_pos) != NULL) + switch (tp->t_oldch) { + /* + * Only blank it out if it is in a room and not + * the border (or other wall) of the room. + */ + case DOOR: + case SECRETDOOR: + case HORZWALL: + case VERTWALL: + break; + + otherwise: + tp->t_oldch = ' '; + } + } + + /* + * If the room is a dark room, we might want to remove + * monsters and the like from it (since they might + * move). + * A dark room. + */ + if ((!lit_room(rp) && (levtype != OUTSIDE)) || + (levtype == OUTSIDE && !daytime) || + on(player, ISBLIND) || + (rp->r_flags & FORCEDARK) || + (levtype == MAZELEV && !see_here && see_before)) { + sch = mvwinch(cw, y, x); /* What's seen */ + rch = mvinch(y, x); /* What's really there */ + switch (rch) { + case DOOR: + case SECRETDOOR: + case STAIRS: + case TRAPDOOR: + case WORMHOLE: + case TELTRAP: + case BEARTRAP: + case SLEEPTRAP: + case ARROWTRAP: + case DARTTRAP: + case MAZETRAP: + case POOL: + case POST: + case VERTWALL: + case HORZWALL: + case WALL: + if (isalpha(sch)) ch = rch; + else if (sch != FLOOR) ch = sch; + else ch = ' '; /* Hide undiscoverd things */ + when FLOOR: + ch = ' '; + otherwise: + ch = ' '; + } + /* Take care of our magic bookkeeping. */ + switch (sch) { + case MAGIC: + case BMAGIC: + case CMAGIC: + ch = sch; + } + } + mvwaddch(cw, y, x, ch); + } + } + } +} + +/* + * lit_room: + * Called to see if the specified room is lit up or not. + */ + +bool +lit_room(rp) +register struct room *rp; +{ + register struct linked_list *fire_item; + register struct thing *fire_creature; + + if (!(rp->r_flags & ISDARK)) return(TRUE); /* A definitely lit room */ + + /* Is it lit by fire light? */ + if (rp->r_flags & HASFIRE) { + switch ((int)levtype) { + case MAZELEV: + /* See if a fire creature is in line of sight */ + for (fire_item = rp->r_fires; fire_item != NULL; + fire_item = next(fire_item)) { + fire_creature = THINGPTR(fire_item); + if (maze_view(fire_creature->t_pos.y, + fire_creature->t_pos.x)) return(TRUE); + } + + /* Couldn't find any in line-of-sight */ + return(FALSE); + + /* We should probably do something special for the outside */ + otherwise: + return TRUE; + } + } + return(FALSE); +} + +/* + * movement: + * Given a pointer to a player/monster structure, calculate the + * movement rate for that character. + */ + +short +movement(tp) +register struct thing *tp; +{ + register int result; + register int carry; /* Percentage carried */ + + result = 0; + + /* Adjust for armor (player only) */ + if (tp == &player && cur_armor) { + int diff; /* Now armor class differs from normal one of same type */ + + /* Blessed armor adds less */ + diff = cur_armor->o_ac - armors[cur_armor->o_which].a_class; + switch (cur_armor->o_which) { + case LEATHER: + case RING_MAIL: + case CHAIN_MAIL: + case SCALE_MAIL: + case PADDED_ARMOR: + diff += 1; + when STUDDED_LEATHER: + case SPLINT_MAIL: + case BANDED_MAIL: + case PLATE_MAIL: + diff += 2; + when PLATE_ARMOR: + diff += 3; + otherwise: + debug("forgot an armor in movement()"); + } + if (diff < 0) diff = 0; + result += diff; + + } + + /* Adjust for the pack */ + carry = 100 * tp->t_stats.s_pack / tp->t_stats.s_carry; + if (carry > 75) result++; + + /* Get a bonus for dexterity */ + result -= dext_plus(tp == &player ? dex_compute() : tp->t_stats.s_dext); + + /* only allow adjust for the minus's */ + if (result < 0) result = 0; + result += tp->t_movement; /* now add in movement rate */ + + /* Is the character slowed? */ + if (on(*tp, ISSLOW) || on(*tp, ISDANCE)) result *= 2; + + /* Is the character hasted? */ + if (on(*tp, ISHASTE)) result /= 2; + + /* We have a minimum of 1 */ + if (result < 1) result = 1; + + return(result); +} + +/* + * rndmove: + * move in a random direction if the monster/person is confused + */ + +coord +rndmove(who) +struct thing *who; +{ + register int x, y; + register int ex, ey, nopen = 0; + coord ret; /* what we will be returning */ + coord dest; + + ret = who->t_pos; + /* + * Now go through the spaces surrounding the player and + * set that place in the array to true if the space can be + * moved into + */ + ey = ret.y + 1; + ex = ret.x + 1; + for (y = who->t_pos.y - 1; y <= ey; y++) + if (y > 0 && y < lines - 2) + for (x = who->t_pos.x - 1; x <= ex; x++) + { + if (x < 0 || x >= cols) + continue; + if (step_ok(y, x, NOMONST, who) == TRUE) + { + dest.y = y; + dest.x = x; + if (!diag_ok(&who->t_pos, &dest, who)) + continue; + if (rnd(++nopen) == 0) + ret = dest; + } + } + return ret; +} + +#define TRAPTYPES 9 /* 9 total trap types that can be set */ +#define WIZARDTRAPS 3 /* Only wizards can set the last 3 */ + /* CTRL(C) to level 400 for POST level */ +static const char *trap_types[TRAPTYPES] = { + "Trap Door", + "Bear Trap", + "Sleep Trap", + "Arrow Trap", + "Teleport Trap", + "Dart Trap", + "Magic pool", + "Maze Trap", + "Worm Hole" +}; + +/* + * set_trap: + * set a trap at (y, x) on screen. + */ + +set_trap(tp, y, x) +register struct thing *tp; +register int y, x; +{ + register bool is_player = (tp == &player); + register int selection = rnd(TRAPTYPES-WIZARDTRAPS) + '1'; + register int i, num_traps; + register unsigned char ch = 0, och; + int thief_bonus = 0; + int s_dext; + + /* let wizard in on this too */ + if (wizard) goto can_traps; + if (is_player && player.t_ctype != C_THIEF && player.t_ctype !=C_ASSASSIN) { + msg("Only thieves and assassins can set traps. "); + return; + } + can_traps: + switch (och = mvinch(y, x)) { + case WALL: + case FLOOR: + case PASSAGE: + break; + default: + if (is_player) msg("The trap failed!"); + return; + } + + if (is_player) { + int state = 0, /* 0 -> current screen, 1 -> prompt screen, 2 -> done */ + units; /* Number of movement units for the given trap */ + + if (player.t_action == C_SETTRAP) { + selection = player.t_selection; + player.t_selection = 0; + player.t_action = A_NIL; + } + else { + msg("Which kind of trap do you wish to set? (* for a list): "); + num_traps = TRAPTYPES - (wizard ? 0 : WIZARDTRAPS); + do { + selection = wgetch(cw); + switch (selection) { + case '*': + if (state != 1) { + wclear(hw); + touchwin(hw); + for (i=0; i<num_traps; i++) { + wmove(hw, i+2, 0); + wprintw(hw, "[%d] %s", i+1, trap_types[i]); + } + mvwaddstr(hw, 0, 0, + "Which kind of trap do you wish to set? "); + + if (menu_overlay) + /* + * Put out the selection. The longest line is + * the prompt line (39 characters long). + */ + over_win(cw, hw, num_traps + 3, 41, 0, 39, NULL); + else + draw(hw); + state = 1; /* Now in prompt window */ + } + break; + + case ESC: + if (state == 1) { + clearok(cw, FALSE); + touchwin(cw); + } + msg(""); + + trap_tries--; /* Don't count this one */ + after = FALSE; + return; + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (selection < '7' || wizard) { + if (state == 1) { /* In prompt window */ + clearok(cw, FALSE); /* Set up for redraw */ + touchwin(cw); + } + + msg(""); + + /* + * Make sure there is a floor below us for trap + * doors. + */ + if (selection == '1' && level >= nfloors) { + if (state == 1) draw(cw); + msg("There is no level below this one."); + return; + } + state = 2; /* Finished */ + break; + } + + /* Fall through for non-wizard, unusual trap case */ + default: + if (state == 1) { /* In the prompt window */ + wmove(hw, 0, 0); + wprintw(hw, + "Please enter a selection between 1 and %d: ", + num_traps); + if (menu_overlay) + /* + * Put out the selection. The longest line is + * the prompt line (43 characters long). + */ + over_win(cw, hw, num_traps+3, 45, 0, 43, NULL); + else + draw(hw); + } + else { /* Normal window */ + mpos = 0; + msg("Please enter a selection between 1 and %d: ", + num_traps); + } + } + } while (state != 2); + + player.t_selection = selection; + + switch (selection) { + case '1': units = 10; /* Trap door */ + when '2': units = 5; /* Bear trap */ + when '3': units = 7; /* Sleeping gas trap */ + when '4': units = 5; /* Arrow trap */ + when '5': units = 10; /* Teleport trap */ + when '6': units = 7; /* Dart trap */ + otherwise: units = 5; /* Unknown trap */ + } + player.t_no_move = units * movement(&player); + player.t_action = C_SETTRAP; + return; + } + } + + if (is_player && player.t_ctype == C_THIEF) thief_bonus = 20; + if (is_player && player.t_ctype == C_ASSASSIN) thief_bonus = 15; + if (is_player && player.t_ctype == C_FIGHTER) thief_bonus = 10; + + s_dext = (tp == &player) ? dex_compute() : tp->t_stats.s_dext; + + if (ntraps >= MAXTRAPS || ++trap_tries >= MAXTRPTRY || + levtype == POSTLEV || levtype == OUTSIDE || + rnd(80) >= (s_dext + tp->t_stats.s_lvl/2 + thief_bonus)) { + if (is_player) msg("The trap failed!"); + return; + } + + switch (selection) { + case '1': ch = TRAPDOOR; + when '2': ch = BEARTRAP; + when '3': ch = SLEEPTRAP; + when '4': ch = ARROWTRAP; + when '5': ch = TELTRAP; + when '6': ch = DARTTRAP; + when '7': ch = POOL; + when '8': ch = MAZETRAP; + when '9': ch = WORMHOLE; + } + + mvaddch(y, x, ch); + traps[ntraps].tr_show = och; + traps[ntraps].tr_type = ch; + traps[ntraps].tr_pos.y = y; + traps[ntraps].tr_pos.x = x; + if (is_player) + traps[ntraps].tr_flags = ISTHIEFSET; + if (ch == POOL || ch == POST) { + traps[ntraps].tr_flags |= ISFOUND; + } + + ntraps++; +} + +/* + * show: + * returns what a certain thing will display as to the un-initiated + */ + +show(y, x) +register int y, x; +{ + register unsigned char ch = winat(y, x); + register struct linked_list *it; + register struct thing *tp; + + if (isatrap(ch)) { + register struct trap *trp = trap_at(y, x); + + return (trp->tr_flags & ISFOUND) ? ch : trp->tr_show; + } + else if (isalpha(ch)) { + if ((it = find_mons(y, x)) == NULL) { + msg("Show: Can't find monster in show (%d, %d)", y, x); + return(mvwinch(stdscr, y, x)); + } + tp = THINGPTR(it); + + if (on(*tp, ISDISGUISE)) ch = tp->t_disguise; /* As a mimic */ + + /* Hide invisible creatures */ + else if (invisible(tp)) { + /* We can't see surprise-type creatures through "see invisible" */ + if (off(player,CANSEE) || on(*tp,CANSURPRISE)) + ch = mvwinch(stdscr, y, x); /* Invisible */ + } + else if (on(*tp, CANINWALL)) { + if (isrock(mvwinch(stdscr, y, x))) ch = winch(stdscr); /* As Xorn */ + } + } + return ch; +} + + +/* + * trap_at: + * find the trap at (y,x) on screen. + */ + +struct trap * +trap_at(y, x) +register int y, x; +{ + register struct trap *tp, *ep; + + ep = &traps[ntraps]; + for (tp = traps; tp < ep; tp++) + if (tp->tr_pos.y == y && tp->tr_pos.x == x) + break; + if (tp == ep) + debug((sprintf(prbuf, "Trap at %d,%d not in array", y, x), prbuf)); + return tp; +} + +/* + * weap_move: + * Calculate how many segments it will take to swing the given + * weapon (note that the weapon may actually be a stick or + * even something else). + */ + +weap_move(wielder, weap) +register struct thing *wielder; /* Who's wielding the weapon */ +register struct object *weap; /* The weapon */ +{ + register int weap_rate; + int dexterity; + int strength; + + if (weap == NULL) return(1); /* hand, claw, bite attacks are quick */ + + switch (weap->o_type) { + case STICK: + if (EQUAL(ws_type[weap->o_which], "staff")) + weap_rate = 2; + else weap_rate = 1; /* A wand */ + + when WEAPON: + weap_rate = weaps[weap->o_which].w_rate; + + /* Adjust for blessed or cursed weapon */ + if (weap->o_hplus < 0) /* Cursed */ + weap_rate -= (weap->o_hplus - 2) / 3; + else if (weap_rate > 0) /* Blessed */ + weap_rate -= (2*weap->o_hplus + weap_rate - 1) / weap_rate; + + when RELIC: + switch (weap->o_which) { + case MUSTY_DAGGER: + case HRUGGEK_MSTAR: + case AXE_AKLAD: + case YEENOGHU_FLAIL: + case MING_STAFF: + case ORCUS_WAND: + case ASMO_ROD: + /* These operate in the blink of an eye */ + weap_rate = 1; + otherwise: + /* What is it? */ + weap_rate = 10; + debug("unknown weapon in weap_move()"); + } + otherwise: + /* What is it? */ + weap_rate = 10; + debug("unknown weapon in weap_move()"); + } + + /* Put in a dexterity bonus */ + if (wielder == &player) dexterity = dex_compute(); + else dexterity = wielder->t_stats.s_dext; + weap_rate -= dext_plus(dexterity) / 2; + + /* Put in a strength bonus */ + if (wielder == &player) strength = str_compute(); + else strength = wielder->t_stats.s_str; + weap_rate -= str_plus(strength) / 2; + + /* It can't speed you up and it must take SOME time */ + if (weap_rate <= 0) weap_rate = 1; + + /* Do we need to adjust for fast/slow movement? */ + if (on(*wielder, ISSLOW) || on(*wielder, ISDANCE)) weap_rate *= 2; + if (on(*wielder, ISHASTE)) weap_rate /= 2; + + /* Return the result */ + return(weap_rate); +} +