view rogue3/move.c @ 81:0e212d46b68f

rogue4: don't put savefile metadata into the savefile. The save_file() function in save.c stored the savefile's device number, inode number, creation time, and modification time in the file. The restore() function read them back, and apparently used to compare them to protect against cheaters. Unfortunately, the types and sizes of these numbers differ from system to system, which ruins the Roguelike Restoration Project's fine portability work. So they have been removed from the savefile. This BREAKS SAVEFILE COMPATIBILITY, but old files can be converted by excising the chunk starting at offset 0x22 with length sizeof(ino_t) + sizeof(dev_t) + 2 * sizeof(time_t). That's 0x14 on i686 and 0x20 on x86_64, at least with current versions of Linux and glibc.
author John "Elwin" Edwards
date Mon, 05 Aug 2013 20:49:41 -0700
parents 527e2150eaf0
children d9e44e18eeec
line wrap: on
line source

/*
 * Hero movement commands
 *
 * @(#)move.c	3.26 (Berkeley) 6/15/81
 *
 * 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 nh;

/*
 * 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;

    firstmove = FALSE;
    if (no_move)
    {
	no_move--;
	msg("You are still stuck in the bear trap");
	return;
    }
    /*
     * Do a confused move (maybe)
     */
    if (rnd(100) < 80 && on(player, ISHUH))
	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 (nh.x < 0 || nh.x > COLS-1 || nh.y < 0 || nh.y > LINES - 1
	|| !diag_ok(&hero, &nh))
    {
	after = FALSE;
	running = FALSE;
	return;
    }
    if (running && ce(hero, nh))
	after = running = FALSE;
    ch = winat(nh.y, nh.x);
    if (on(player, ISHELD) && ch != 'F')
    {
	msg("You are being held");
	return;
    }
    switch(ch)
    {
	case ' ':
	case '|':
	case '-':
	case SECRETDOOR:
	    after = running = FALSE;
	    return;
	case TRAP:
	    ch = be_trapped(&nh);
	    if (ch == TRAPDOOR || ch == TELTRAP)
		return;
	    goto move_stuff;
	case GOLD:
	case POTION:
	case SCROLL:
	case FOOD:
	case WEAPON:
	case ARMOR:
	case RING:
	case AMULET:
	case STICK:
	    running = FALSE;
	    take = ch;
	default:
move_stuff:
	    if (ch == PASSAGE && winat(hero.y, hero.x) == DOOR)
		light(&hero);
	    else if (ch == DOOR)
	    {
		running = FALSE;
		if (winat(hero.y, hero.x) == PASSAGE)
		    light(&nh);
	    }
	    else if (ch == STAIRS)
		running = FALSE;
	    else if (isupper(ch))
	    {
		running = FALSE;
		fight(&nh, ch, cur_weapon, FALSE);
		return;
	    }
	    ch = winat(hero.y, hero.x);
	    wmove(cw, unc(hero));
	    waddch(cw, ch);
	    hero = nh;
	    wmove(cw, unc(hero));
	    waddch(cw, PLAYER);
    }
}

/*
 * Called to illuminate a room.
 * If it is dark, remove anything that might move.
 */

void
light(coord *cp)
{
    struct room *rp;
    int j, k;
    int ch;
    int rch;
    struct linked_list *item;

    if ((rp = roomin(cp)) != NULL && !on(player, ISBLIND))
    {
	for (j = 0; j < rp->r_max.y; j++)
	{
	    for (k = 0; k < rp->r_max.x; k++)
	    {
		ch = show(rp->r_pos.y + j, rp->r_pos.x + k);
		wmove(cw, rp->r_pos.y + j, rp->r_pos.x + k);
		/*
		 * Figure out how to display a secret door
		 */
		if (ch == SECRETDOOR)
		{
		    if (j == 0 || j == rp->r_max.y - 1)
			ch = '-';
		    else
			ch = '|';
		}
		/*
		 * If the room is a dark room, we might want to remove
		 * monsters and the like from it (since they might
		 * move)
		 */
		if (isupper(ch))
		{
		    item = wake_monster(rp->r_pos.y+j, rp->r_pos.x+k);
		    if (((struct thing *) ldata(item))->t_oldch == ' ')
			if (!(rp->r_flags & ISDARK))
			    ((struct thing *) ldata(item))->t_oldch =
				mvwinch(stdscr, rp->r_pos.y+j, rp->r_pos.x+k);
		}
		if (rp->r_flags & ISDARK)
		{
		    rch = mvwinch(cw, rp->r_pos.y+j, rp->r_pos.x+k);
		    switch (rch)
		    {
			case DOOR:
			case STAIRS:
			case TRAP:
			case '|':
			case '-':
			case ' ':
			    ch = rch;
			when FLOOR:
			    ch = (on(player, ISBLIND) ? FLOOR : ' ');
			otherwise:
			    ch = ' ';
		    }
		}
		mvwaddch(cw, rp->r_pos.y+j, rp->r_pos.x+k, ch);
	    }
	}
    }
}

/*
 * show:
 *	returns what a certain thing will display as to the un-initiated
 */

int
show(int y, int x)
{
    int ch = winat(y, x);
    struct linked_list *it;
    struct thing *tp;

    if (ch == TRAP)
	return (trap_at(y, x)->tr_flags & ISFOUND) ? TRAP : FLOOR;
    else if (ch == 'M' || ch == 'I')
    {
	if ((it = find_mons(y, x)) == NULL)
	    fatal("Can't find monster in show");
	tp = (struct thing *) ldata(it);
	if (ch == 'M')
	    ch = tp->t_disguise;
	/*
	 * Hide invisible monsters
	 */
	else if (off(player, CANSEE))
	    ch = mvwinch(stdscr, y, x);
    }
    return ch;
}

/*
 * be_trapped:
 *	The guy stepped on a trap.... Make him pay.
 */

int
be_trapped(coord *tc)
{
    struct trap *tp;
    int ch;

    tp = trap_at(tc->y, tc->x);
    count = running = FALSE;
    mvwaddch(cw, tp->tr_pos.y, tp->tr_pos.x, TRAP);
    tp->tr_flags |= ISFOUND;
    switch (ch = tp->tr_type)
    {
	case TRAPDOOR:
	    level++;
	    new_level();
	    msg("You fell into a trap!");
	when BEARTRAP:
	    no_move += BEARTIME;
	    msg("You are caught in a bear trap");
	when SLEEPTRAP:
	    no_command += SLEEPTIME;
	    msg("A strange white mist envelops you and you fall asleep");
	when ARROWTRAP:
	    if (swing(pstats.s_lvl-1, pstats.s_arm, 1))
	    {
		msg("Oh no! An arrow shot you");
		if ((pstats.s_hpt -= roll(1, 6)) <= 0)
		{
		    msg("The arrow killed you.");
		    death('a');
		}
	    }
	    else
	    {
		struct linked_list *item;
		struct object *arrow;

		msg("An arrow shoots past you.");
		item = new_item(sizeof *arrow);
		arrow = (struct object *) ldata(item);
		arrow->o_type = WEAPON;
		arrow->o_which = ARROW;
		init_weapon(arrow, ARROW);
		arrow->o_count = 1;
		arrow->o_pos = hero;
		arrow->o_hplus = arrow->o_dplus = 0; /* "arrow bug" FIX */
		fall(item, FALSE);
	    }
	when TELTRAP:
	    teleport();
	when DARTTRAP:
	    if (swing(pstats.s_lvl+1, pstats.s_arm, 1))
	    {
		msg("A small dart just hit you in the shoulder");
		if ((pstats.s_hpt -= roll(1, 4)) <= 0)
		{
		    msg("The dart killed you.");
		    death('d');
		}
		if (!ISWEARING(R_SUSTSTR))
		    chg_str(-1);
	    }
	    else
		msg("A small dart whizzes by your ear and vanishes.");
    }
    flush_type();	/* flush typeahead */
    return(ch);
}

/*
 * trap_at:
 *	find the trap at (y,x) on screen.
 */

struct trap *
trap_at(int y, int x)
{
    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)
    {
	sprintf(prbuf, "Trap at %d,%d not in array", y, x);
	fatal(prbuf);
    }
    return tp;
}

/*
 * rndmove:
 *	move in a random direction if the monster/person is confused
 */

coord *
rndmove(struct thing *who)
{
    int x, y;
    int ch;
    int ex, ey, nopen = 0;
    struct linked_list *item;
    struct object *obj;
    static coord ret;  /* what we will be returning */
    static 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)
	    for (x = who->t_pos.x - 1; x <= ex; x++)
	    {
		if (x < 0 || x >= COLS)
		    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)
		    {
			item = NULL;
			for (item = lvl_obj; item != NULL; item = next(item))
			{
			    obj = (struct object *) ldata(item);
			    if (y == obj->o_pos.y && x == obj->o_pos.x)
				break;
			}
			if (item != NULL && obj->o_which == S_SCARE)
			    continue;
		    }
		    if (rnd(++nopen) == 0)
			ret = dest;
		}
	    }
    return &ret;
}