/* * Hero movement commands * * @(#)move.c 9.0 (rdk) 7/17/84 * * Super-Rogue * Copyright (C) 1984 Robert D. Kindelberger * 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 #include #include "rogue.h" #include "rogue.ext" /* * Used to hold the new hero position */ struct coord nh; /* * do_run: * Start the hero running */ void do_run(char ch) { running = TRUE; after = FALSE; runch = ch; } /* * do_move: * Check to see that a move is legal. If it is handle the * consequences (fighting, picking up, etc.) */ void do_move(int dy, int dx) { reg int ch; reg struct room *rp; firstmove = FALSE; curprice = -1; inpool = FALSE; if (player.t_nomove > 0) { player.t_nomove -= 1; msg("You are still stuck in the bear trap."); return; } /* * Do a confused move (maybe) */ if ((rnd(100) < 80 && pl_on(ISHUH)) || (iswearing(R_DELUS) && rnd(100) < 25)) nh = *rndmove(&player); else { nh.y = hero.y + dy; 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 (!cordok(nh.y, nh.x) || (pl_off(ISETHER) && !diag_ok(&hero, &nh))) { after = running = FALSE; return; } if (running) { ch = winat(nh.y, nh.x); if (dead_end(ch)) { reg int gox, goy, apsg, whichway; gox = goy = apsg = 0; if (dy == 0) { ch = show(hero.y+1,hero.x); if (ch == PASSAGE) { apsg += 1; goy = 1; } ch = show(hero.y-1,hero.x); if (ch == PASSAGE) { apsg += 1; goy = -1; } } else if (dx == 0) { ch = show(hero.y,hero.x+1); if (ch == PASSAGE) { gox = 1; apsg += 1; } ch = show(hero.y,hero.x-1); if (ch == PASSAGE) { gox = -1; apsg += 1; } } if (apsg != 1) { running = after = FALSE; return; } else { /* can still run here */ nh.y = hero.y + goy; nh.x = hero.x + gox; whichway = (goy + 1) * 3 + gox + 1; switch(whichway) { case 0: runch = 'y'; when 1: runch = 'k'; when 2: runch = 'u'; when 3: runch = 'h'; when 4: runch = '.'; /* shouldn't do */ when 5: runch = 'l'; when 6: runch = 'b'; when 7: runch = 'j'; when 8: runch = 'n'; } } } } if (running && ce(hero, nh)) after = running = FALSE; ch = winat(nh.y, nh.x); if (pl_on(ISHELD) && ch != 'F' && ch != 'd') { msg("You are being held."); return; } if (pl_off(ISETHER)) { if (isatrap(ch)) { ch = be_trapped(&nh, &player); if (nlmove) { nlmove = FALSE; return; } else if (ch == POOL) inpool = TRUE; } else if (dead_end(ch)) { after = running = FALSE; return; } else { switch(ch) { case GOLD: case POTION: case SCROLL: case FOOD: case WEAPON: case ARMOR: case RING: case AMULET: case STICK: running = FALSE; take = ch; default: if (illeg_ch(ch)) { running = FALSE; mvaddch(nh.y, nh.x, FLOOR); teleport(rndspot, &player); light(&nh); msg("The spatial warp disappears !"); return; } } } } rp = roomin(&nh); if (ch == DOOR) { /* just stepped on a door */ running = FALSE; if (rp != NULL && rf_on(rp, ISTREAS)) { struct linked_list *item; struct thing *tp; for (item = mlist; item != NULL; item = next(item)) { tp = THINGPTR(item); if (tp->t_room == rp) runto(&tp->t_pos, &hero); } } } else if (ch == STAIRS && pl_off(ISETHER)) running = FALSE; else if (isalpha(ch) && pl_off(ISETHER)) { running = FALSE; fight(&nh, cur_weapon, FALSE); return; } if (rp == NULL && player.t_room != NULL) light(&hero); /* exiting a room */ else if (rp != NULL && player.t_room == NULL) light(&nh); /* just entering a room */ if (pl_on(ISBLIND)) ch = ' '; else ch = player.t_oldch; mvwaddch(cw, hero.y, hero.x, ch); mvwaddch(cw, nh.y, nh.x, PLAYER); hero = nh; player.t_room = rp; player.t_oldch = mvinch(hero.y, hero.x); } /* * Called to illuminate a room. * If it is dark, remove anything that might move. */ void light(struct coord *cp) { reg struct room *rp; reg int j, k, x, y; reg char ch, rch; reg struct linked_list *item; rp = roomin(cp); if (rp == NULL) return; if (pl_on(ISBLIND)) { for (j = 0; j < rp->r_max.y; j += 1) { for (k = 0; k < rp->r_max.x; k += 1) { y = rp->r_pos.y + j; x = rp->r_pos.x + k; mvwaddch(cw, y, x, ' '); } } look(FALSE); return; } if (iswearing(R_LIGHT)) rp->r_flags &= ~ISDARK; for (j = 0; j < rp->r_max.y; j += 1) { for (k = 0; k < rp->r_max.x; k += 1) { y = rp->r_pos.y + j; x = rp->r_pos.x + k; if (levtype == MAZELEV && !cansee(y, x)) 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 = '-'; else ch = '|'; } if (isalpha(ch)) { struct thing *mit; item = wake_monster(y, x); if (item == NULL) { ch = FLOOR; mvaddch(y, x, ch); } else { mit = THINGPTR(item); if (mit->t_oldch == ' ') if (!rf_on(rp,ISDARK)) mit->t_oldch = mvinch(y, x); if (levtype == MAZELEV) ch = mvinch(y, x); } } if (rf_on(rp,ISDARK)) { rch = mvwinch(cw, y, x); if (isatrap(rch)) { ch = rch; /* if its a trap */ } else { /* try other things */ switch (rch) { case DOOR: case STAIRS: case '|': case '-': ch = rch; otherwise: ch = ' '; } } } mvwaddch(cw, y, x, ch); } } } /* * show: * returns what a certain thing will display as to the un-initiated */ char show(int y, int x) { reg char ch = winat(y, x); reg struct linked_list *it; reg struct thing *tp; reg struct trap *ta; if (isatrap(ch)) { if ((ta = trap_at(y, x)) == NULL) return FLOOR; if (iswearing(R_FTRAPS)) ta->tr_flags |= ISFOUND; return ((ta->tr_flags & ISFOUND) ? ta->tr_type : FLOOR); } if (ch == SECRETDOOR && iswearing(R_FTRAPS)) { mvaddch(y,x,DOOR); return DOOR; } if ((it = find_mons(y, x)) != NULL) { /* maybe a monster */ tp = THINGPTR(it); if (ch == 'M' || (tp->t_flags & ISINVIS)) { if (ch == 'M') ch = tp->t_disguise; else if (pl_off(CANSEE)) { if (ch == 's') ch = ' '; /* shadows show as a blank */ else ch = mvinch(y, x); /* hide invisibles */ } } } return ch; } /* * be_trapped: * Hero or monster stepped on a trap. */ int be_trapped(struct coord *tc, struct thing *th) { reg struct trap *trp; reg int ch, ishero; struct linked_list *mon; char stuckee[35], seeit, sayso; if ((trp = trap_at(tc->y, tc->x)) == NULL) return 0; ishero = (th == &player); if (ishero) { strcpy(stuckee, "You"); count = running = FALSE; } else { sprintf(stuckee, "The %s", monsters[th->t_indx].m_name); } seeit = cansee(tc->y, tc->x); if (seeit) mvwaddch(cw, tc->y, tc->x, trp->tr_type); trp->tr_flags |= ISFOUND; sayso = TRUE; switch (ch = trp->tr_type) { case POST: if (ishero) { nlmove = TRUE; new_level(POSTLEV); } else goto goner; when MAZETRAP: if (ishero) { nlmove = TRUE; level += 1; new_level(MAZELEV); msg("You are surrounded by twisty passages!"); } else goto goner; when TELTRAP: nlmove = TRUE; teleport(trp->tr_goto, th); when TRAPDOOR: if (ishero) { level += 1; new_level(NORMLEV); } else { /* monsters get lost */ goner: ch = GONER; } nlmove = TRUE; if (seeit && sayso) msg("%s fell into a trap!", stuckee); when BEARTRAP: th->t_nomove += BEARTIME; if (seeit) { strcat(stuckee, (ishero ? " are" : " is")); msg("%s caught in a bear trap.", stuckee); } when SLEEPTRAP: if (ishero && pl_on(ISINVINC)) msg("You feel momentarily dizzy."); else { if (ishero) th->t_nocmd += SLEEPTIME; else th->t_nomove += SLEEPTIME; if (seeit) msg("%s fall%s asleep in a strange white mist.", stuckee, (ishero ? "":"s")); } when ARROWTRAP: { int resist, ac; struct stats *it; stuckee[0] = tolower(stuckee[0]); it = &th->t_stats; if (ishero && cur_armor != NULL) ac = cur_armor->o_ac; else ac = it->s_arm; resist = ac + getpdex(it, FALSE); if (ishero && pl_on(ISINVINC)) resist = -100; /* invincible is impossible to hit */ if (swing(3 + (level / 4), resist, 1)) { if (seeit) msg("%sAn arrow shot %s.", (ishero ? "Oh no! " : ""), stuckee); if (ishero) chg_hpt(-roll(1,6),FALSE,K_ARROW); else { it->s_hpt -= roll(1,6); if (it->s_hpt < 1) { sayso = FALSE; goto goner; } } } else { struct linked_list *item; struct object *arrow; if (seeit) msg("An arrow shoots past %s.", stuckee); item = new_thing(FALSE, WEAPON, ARROW); arrow = OBJPTR(item); arrow->o_hplus = 3; arrow->o_dplus = rnd(2); arrow->o_count = 1; arrow->o_pos = th->t_pos; fall(item, FALSE); } } when DARTTRAP: { int resist, ac; struct stats *it; stuckee[0] = tolower(stuckee[0]); it = &th->t_stats; if (ishero && cur_armor != NULL) ac = cur_armor->o_ac; else ac = it->s_arm; resist = ac + getpdex(it, FALSE); if (ishero && pl_on(ISINVINC)) resist = -100; /* invincible is impossible to hit */ if (swing(3 + (level / 4), resist, 0)) { if (seeit) msg("A small dart just hit %s.", stuckee); if (ishero) { if (!save(VS_POISON)) chg_abil(CON,-1,TRUE); if (!iswearing(R_SUSTSTR)) chg_abil(STR,-1,TRUE); chg_hpt(-roll(1, 4),FALSE,K_DART); } else { if (!save_throw(VS_POISON, th)) it->s_ef.a_str -= 1; it->s_hpt -= roll(1, 4); if (it->s_hpt < 1) { sayso = FALSE; goto goner; } } } else if (seeit) msg("A small dart whizzes by %s.", stuckee); } when POOL: if (!ishero && rnd(100) < 10) { if (seeit) msg("The %s drowns !!", stuckee); goto goner; } if ((trp->tr_flags & ISGONE) && rnd(100) < 10) { nlmove = TRUE; if (rnd(100) < 15) teleport(rndspot, th); /* teleport away */ else if(rnd(100) < 15 && level > 2) { level -= rnd(2) + 1; new_level(NORMLEV); msg("You here a faint groan from below."); } else if(rnd(100) < 40) { level += rnd(4); new_level(NORMLEV); msg("You find yourself in strange surroundings."); } else if(rnd(100) < 6 && pl_off(ISINVINC)) { msg("Oh no!!! You drown in the pool!!! --More--"); wait_for(cw, ' '); death(K_POOL); } else nlmove = FALSE; } } flushinp(); /* flush typeahead */ return ch; } /* * dip_it: * Dip an object into a magic pool */ void dip_it(void) { reg struct linked_list *what; reg struct object *ob; reg struct trap *tp; reg int wh; tp = trap_at(hero.y,hero.x); if (tp == NULL || inpool == FALSE || (tp->tr_flags & ISGONE)) return; if ((what = get_item("dip",0)) == NULL) return; ob = OBJPTR(what); mpos = 0; /* * If hero is trying to dip an object OTHER than his * current weapon, make sure that he could drop his * current weapon */ if (ob != cur_weapon) { if (cur_weapon != NULL && o_on(cur_weapon, ISCURSED)) { msg("You are unable to release your weapon."); after = FALSE; return; } } if (ob == cur_armor) { msg("You have to take off your armor before you can dip it."); after = FALSE; return; } else if (ob == cur_ring[LEFT] || ob == cur_ring[RIGHT]) { msg("You have to take that ring off before you can dip it."); after = FALSE; return; } wh = ob->o_which; tp->tr_flags |= ISGONE; if (ob != NULL && o_off(ob,ISPROT)) { setoflg(ob,ISKNOW); switch(ob->o_type) { case WEAPON: if(rnd(100) < 20) { /* enchant weapon here */ if (o_off(ob,ISCURSED)) { ob->o_hplus += 1; ob->o_dplus += 1; } else { /* weapon was prev cursed here */ ob->o_hplus = rnd(2); ob->o_dplus = rnd(2); } resoflg(ob,ISCURSED); } else if(rnd(100) < 10) { /* curse weapon here */ if (o_off(ob,ISCURSED)) { ob->o_hplus = -(rnd(2)+1); ob->o_dplus = -(rnd(2)+1); } else { /* if already cursed */ ob->o_hplus--; ob->o_dplus--; } setoflg(ob,ISCURSED); } msg("The %s glows for a moment.",w_magic[wh].mi_name); when ARMOR: if (rnd(100) < 30) { /* enchant armor */ if(o_off(ob,ISCURSED)) ob->o_ac -= rnd(2) + 1; else ob->o_ac = -rnd(3)+ armors[wh].a_class; resoflg(ob,ISCURSED); } else if(rnd(100) < 15){ /* curse armor */ if (o_off(ob,ISCURSED)) ob->o_ac = rnd(3)+ armors[wh].a_class; else ob->o_ac += rnd(2) + 1; setoflg(ob,ISCURSED); } msg("The %s glows for a moment.",a_magic[wh].mi_name); when STICK: { int i; struct rod *rd; i = rnd(8) + 1; if(rnd(100) < 25) /* add charges */ ob->o_charges += i; else if(rnd(100) < 10) { /* remove charges */ if ((ob->o_charges -= i) < 0) ob->o_charges = 0; } ws_know[wh] = TRUE; rd = &ws_stuff[wh]; msg("The %s %s glows for a moment.",rd->ws_made,rd->ws_type); } 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: r_know[wh] = TRUE; if (magring(ob)) { if(rnd(100) < 25) { /* enchant ring */ if (o_off(ob,ISCURSED)) ob->o_ac += rnd(2) + 1; else ob->o_ac = rnd(2) + 1; resoflg(ob,ISCURSED); } else if(rnd(100) < 10) { /* curse ring */ if (o_off(ob,ISCURSED)) ob->o_ac = -(rnd(2) + 1); else ob->o_ac -= (rnd(2) + 1); setoflg(ob,ISCURSED); } } msg("The %s ring vibrates for a moment.",r_stones[wh]); otherwise: msg("The pool bubbles for a moment."); } } cur_weapon = ob; /* hero has to weild item to dip it */ } /* * trap_at: * Find the trap at (y,x) on screen. */ struct trap * trap_at(int y, int x) { reg struct trap *tp, *ep; ep = &traps[ntraps]; for (tp = traps; tp < ep; tp += 1) if (tp->tr_pos.y == y && tp->tr_pos.x == x) break; if (tp >= ep) tp = NULL; return tp; } /* * rndmove: * move in a random direction if the monster/person is confused */ struct coord * rndmove(struct thing *who) { reg int x, y, ex, ey, ch; int nopen = 0; struct linked_list *item; static struct coord ret; /* what we will be returning */ static struct 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 += 1) { for (x = who->t_pos.x - 1; x <= ex; x += 1) { if (!cordok(y, x)) continue; ch = winat(y, x); if (step_ok(ch)) { dest.y = y; dest.x = x; if (!diag_ok(&who->t_pos, &dest)) continue; if (ch == SCROLL && who != &player) { /* * check for scare monster scrolls */ item = find_obj(y, x); if (item != NULL && (OBJPTR(item))->o_which == S_SCARE) continue; } if (rnd(++nopen) == 0) ret = dest; } } } return &ret; } /* * isatrap: * Returns TRUE if this character is some kind of trap */ bool isatrap(char ch) { switch(ch) { case POST: case DARTTRAP: case POOL: case TELTRAP: case TRAPDOOR: case ARROWTRAP: case SLEEPTRAP: case BEARTRAP: case MAZETRAP: return TRUE; default: return FALSE; } }