Mercurial > hg > early-roguelike
view rogue5/move.c @ 132:66b0263af424
arogue7: prevent segfaults when backstabbing while empty-handed.
The calculation of the backstabbing multiplier checked the current
weapon's properties without making sure the current weapon pointer was
not NULL.
author | John "Elwin" Edwards |
---|---|
date | Tue, 12 May 2015 18:57:30 -0400 |
parents | f502bf60e6e4 |
children |
line wrap: on
line source
/* * hero movement commands * * @(#)move.c 4.49 (Berkeley) 02/05/99 * * Rogue: Exploring the Dungeons of Doom * Copyright (C) 1980-1983, 1985, 1999 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 */ /* * do_run: * Start the hero running */ void do_run(int 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) { int ch, fl; coord nh; firstmove = FALSE; if (no_move) { no_move--; msg("you are still stuck in the bear trap"); return; } /* * Do a confused move (maybe) */ if (on(player, ISHUH) && rnd(5) != 0) { nh = rndmove(&player); if (ce(nh, hero)) { after = FALSE; running = FALSE; to_death = FALSE; return; } } else { over: 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 (nh.x < 0 || nh.x >= NUMCOLS || nh.y <= 0 || nh.y >= NUMLINES - 1) goto hit_bound; if (!diag_ok(&hero, &nh)) { after = FALSE; running = FALSE; return; } if (running && ce(hero, nh)) after = running = FALSE; fl = flat(nh.y, nh.x); ch = winat(nh.y, nh.x); if (!(fl & F_REAL) && ch == FLOOR) { if (!on(player, ISLEVIT)) { chat(nh.y, nh.x) = ch = TRAP; flat(nh.y, nh.x) |= F_REAL; } } else if (on(player, ISHELD) && ch != 'F') { msg("you are being held"); return; } switch (ch) { case ' ': case '|': case '-': hit_bound: if (passgo && running && (proom->r_flags & ISGONE) && !on(player, ISBLIND)) { int b1, b2; switch (runch) { case 'h': case 'l': b1 = (hero.y != 1 && turn_ok(hero.y - 1, hero.x)); b2 = (hero.y != NUMLINES - 2 && turn_ok(hero.y + 1, hero.x)); if (!(b1 ^ b2)) break; if (b1) { runch = 'k'; dy = -1; } else { runch = 'j'; dy = 1; } dx = 0; turnref(); goto over; case 'j': case 'k': b1 = (hero.x != 0 && turn_ok(hero.y, hero.x - 1)); b2 = (hero.x != NUMCOLS - 1 && turn_ok(hero.y, hero.x + 1)); if (!(b1 ^ b2)) break; if (b1) { runch = 'h'; dx = -1; } else { runch = 'l'; dx = 1; } dy = 0; turnref(); goto over; } } running = FALSE; after = FALSE; break; case DOOR: running = FALSE; if (flat(hero.y, hero.x) & F_PASS) enter_room(&nh); goto move_stuff; case TRAP: ch = be_trapped(&nh); if (ch == T_DOOR || ch == T_TELEP) return; goto move_stuff; case PASSAGE: /* * when you're in a corridor, you don't know if you're in * a maze room or not, and there ain't no way to find out * if you're leaving a maze room, so it is necessary to * always recalculate proom. */ proom = roomin(&hero); goto move_stuff; case FLOOR: if (!(fl & F_REAL)) be_trapped(&hero); goto move_stuff; case STAIRS: seenstairs = TRUE; /* FALLTHROUGH */ default: running = FALSE; if (isupper(ch) || moat(nh.y, nh.x)) fight(&nh, cur_weapon, FALSE); else { if (ch != STAIRS) take = ch; move_stuff: mvaddch(hero.y, hero.x, floor_at()); if ((fl & F_PASS) && chat(oldpos.y, oldpos.x) == DOOR) leave_room(&nh); hero = nh; } } } /* * turn_ok: * Decide whether it is legal to turn onto the given space */ int turn_ok(int y, int x) { PLACE *pp; pp = INDEX(y, x); return (pp->p_ch == DOOR || (pp->p_flags & (F_REAL|F_PASS)) == (F_REAL|F_PASS)); } /* * turnref: * Decide whether to refresh at a passage turning or not */ void turnref(void) { PLACE *pp; pp = INDEX(hero.y, hero.x); if (!(pp->p_flags & F_SEEN)) { if (jump) { leaveok(stdscr, TRUE); refresh(); leaveok(stdscr, FALSE); } pp->p_flags |= F_SEEN; } } /* * door_open: * Called to illuminate a room. If it is dark, remove anything * that might move. */ void door_open(const struct room *rp) { int y, x; if (!(rp->r_flags & ISGONE)) for (y = rp->r_pos.y; y < rp->r_pos.y + rp->r_max.y; y++) for (x = rp->r_pos.x; x < rp->r_pos.x + rp->r_max.x; x++) if (isupper(winat(y, x))) wake_monster(y, x); } /* * be_trapped: * The guy stepped on a trap.... Make him pay. */ int be_trapped(const coord *tc) { PLACE *pp; THING *arrow; int tr; if (on(player, ISLEVIT)) return T_RUST; /* anything that's not a door or teleport */ running = FALSE; count = FALSE; pp = INDEX(tc->y, tc->x); pp->p_ch = TRAP; tr = pp->p_flags & F_TMASK; pp->p_flags |= F_SEEN; switch (tr) { case T_DOOR: level++; new_level(); msg("you fell into a trap!"); when T_BEAR: no_move += BEARTIME; msg("you are caught in a bear trap"); when T_MYST: switch(rnd(11)) { case 0: msg("you are suddenly in a parallel dimension"); when 1: msg("the light in here suddenly seems %s", rainbow[rnd(cNCOLORS)]); when 2: msg("you feel a sting in the side of your neck"); when 3: msg("multi-colored lines swirl around you, then fade"); when 4: msg("a %s light flashes in your eyes", rainbow[rnd(cNCOLORS)]); when 5: msg("a spike shoots past your ear!"); when 6: msg("%s sparks dance across your armor", rainbow[rnd(cNCOLORS)]); when 7: msg("you suddenly feel very thirsty"); when 8: msg("you feel time speed up suddenly"); when 9: msg("time now seems to be going slower"); when 10: msg("you pack turns %s!", rainbow[rnd(cNCOLORS)]); } when T_SLEEP: no_command += SLEEPTIME; player.t_flags &= ~ISRUN; msg("a strange white mist envelops you and you fall asleep"); when T_ARROW: if (swing(pstats.s_lvl - 1, pstats.s_arm, 1)) { pstats.s_hpt -= roll(1, 6); if (pstats.s_hpt <= 0) { msg("an arrow killed you"); death('a'); } else msg("oh no! An arrow shot you"); } else { arrow = new_item(); init_weapon(arrow, ARROW); arrow->o_count = 1; arrow->o_pos = hero; fall(arrow, FALSE); msg("an arrow shoots past you"); } when T_TELEP: /* * since the hero's leaving, look() won't put a TRAP * down for us, so we have to do it ourself */ teleport(); mvaddch(tc->y, tc->x, TRAP); when T_DART: if (!swing(pstats.s_lvl+1, pstats.s_arm, 1)) msg("a small dart whizzes by your ear and vanishes"); else { pstats.s_hpt -= roll(1, 4); if (pstats.s_hpt <= 0) { msg("a poisoned dart killed you"); death('d'); } if (!ISWEARING(R_SUSTSTR) && !save(VS_POISON)) chg_str(-1); msg("a small dart just hit you in the shoulder"); } when T_RUST: msg("a gush of water hits you on the head"); rust_armor(cur_armor); } flush_type(); return tr; } /* * rndmove: * Move in a random direction if the monster/person is confused */ coord rndmove(const THING *who) { THING *obj; int x, y; int ch; coord ret; /* what we will be returning */ y = ret.y = who->t_pos.y + rnd(3) - 1; x = ret.x = who->t_pos.x + rnd(3) - 1; /* * Now check to see if that's a legal move. If not, don't move. * (I.e., bump into the wall or whatever) */ if (y == who->t_pos.y && x == who->t_pos.x) return ret; if (!diag_ok(&who->t_pos, &ret)) goto bad; else { ch = winat(y, x); if (!step_ok(ch)) goto bad; if (ch == SCROLL) { for (obj = lvl_obj; obj != NULL; obj = next(obj)) if (y == obj->o_pos.y && x == obj->o_pos.x) break; if (obj != NULL && obj->o_which == S_SCARE) goto bad; } } return ret; bad: ret = who->t_pos; return ret; } /* * rust_armor: * Rust the given armor, if it is a legal kind to rust, and we * aren't wearing a magic ring. */ void rust_armor(THING *arm) { if (arm == NULL || arm->o_type != ARMOR || arm->o_which == LEATHER || arm->o_arm >= 9) return; if ((arm->o_flags & ISPROT) || ISWEARING(R_SUSTARM)) { if (!to_death) msg("the rust vanishes instantly"); } else { arm->o_arm++; if (!terse) msg("your armor appears to be weaker now. Oh my!"); else msg("your armor weakens"); } }