diff urogue/move.c @ 256:c495a4f288c6

Import UltraRogue from the Roguelike Restoration Project (r1490)
author John "Elwin" Edwards
date Tue, 31 Jan 2017 19:56:04 -0500
parents
children e52a8a7ad4c5
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/move.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,1837 @@
+/*
+    move.c - Hero movement commands
+      
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
+    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 <stdlib.h>
+#include <ctype.h>
+#include "rogue.h"
+
+/*
+    do_run()
+        Start the hero running
+*/
+
+void
+do_run(char ch)
+{
+    running = TRUE;
+    after = FALSE;
+    runch = ch;
+
+    if (doorstop && !on(player, ISBLIND))
+    {
+        door_stop = TRUE;
+        firstmove = TRUE;
+    }
+}
+
+/*
+    step_ok()
+        returns true if it is ok for type to step on ch flgptr will be
+        NULL if we don't know what the monster is yet!
+*/
+
+int
+step_ok(int y, int x, int can_on_monst, struct thing *flgptr)
+{
+    struct linked_list *item;
+    char ch;
+
+    /* What is here?  Don't check monster window if MONSTOK is set */
+
+    if (can_on_monst == MONSTOK)
+        ch = CCHAR( mvinch(y, x) );
+    else
+        ch = winat(y, x);
+
+    switch (ch)
+    {
+        case ' ':
+        case '|':
+        case '-':
+        case SECRETDOOR:
+            if (flgptr && on(*flgptr, CANINWALL))
+                return(TRUE);
+
+            return(FALSE);
+
+        case SCROLL:
+            /*
+             * If it is a scroll, it might be a scare monster scroll so
+             * we need to look it up to see what type it is.
+             */
+
+            if (flgptr && flgptr->t_ctype == C_MONSTER)
+            {
+                item = find_obj(y, x);
+
+                if (item != NULL && (OBJPTR(item))->o_type == SCROLL
+                     && (OBJPTR(item))->o_which == S_SCARE
+                     && rnd(flgptr->t_stats.s_intel) < 12)
+                return(FALSE); /* All but smart ones are scared */
+            }
+            return(TRUE);
+
+        default:
+            return(!isalpha(ch));
+    }
+}
+
+/*
+    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.
+*/
+
+void
+corr_move(int dy, int dx)
+{
+    char    ch;
+    short   legal = 0;  /* Number of legal alternatives */
+    int     y = 0, x = 0;   /* Holds legal new position */
+    int    *ny, *nx;    /* Point to which direction to change */
+
+    /* New position */
+
+    player.t_nxtpos.y = hero.y + dy;
+    player.t_nxtpos.x = hero.x + dx;
+
+    /* A bad diagonal move is illegal */
+
+    if (!diag_ok(&hero, &player.t_nxtpos, &player))
+        return;
+
+    /* If it is a legal move, just return */
+
+    if (player.t_nxtpos.x >= 0 && player.t_nxtpos.x < COLS && player.t_nxtpos.y > 0 && player.t_nxtpos.y < LINES - 2)
+    {
+        ch = winat(player.t_nxtpos.y, player.t_nxtpos.x);
+
+        switch (ch)
+        {
+            case ' ':
+            case '|':
+            case '-':
+                break;
+            default:
+                return;
+        }
+    }
+
+    /* Check the legal alternatives */
+
+    if (dy == 0)
+    {
+        ny = &dy;
+        nx = &dx;
+    }
+    else
+    {
+        ny = &dx;
+        nx = &dy;
+    }
+
+    for (*nx = 0, *ny = -1; *ny < 2; *ny += 2)
+    {
+        /* New position */
+        player.t_nxtpos.y = hero.y + dy;
+        player.t_nxtpos.x = hero.x + dx;
+
+        if (player.t_nxtpos.x < 0 || player.t_nxtpos.x > COLS - 1 || player.t_nxtpos.y < 1 || player.t_nxtpos.y > LINES - 3)
+            continue;
+
+        ch = winat(player.t_nxtpos.y, player.t_nxtpos.x);
+
+        switch (ch)
+        {
+            case ' ':
+            case '|':
+            case '-':
+                break;
+            default:
+                legal++;
+                y = dy;
+                x = dx;
+        }
+    }
+
+    /* If we have 2 legal moves, make no change */
+
+    if (legal != 1)
+        return;
+
+    /* Make the change */
+
+    if (y == 0)         /* Move horizontally */
+    {
+        if (x == 1)
+            runch = 'l';
+        else
+            runch = 'h';
+    }
+    else            /* Move vertically */
+    {
+        if (y == 1)
+            runch = 'j';
+        else
+            runch = 'k';
+    }
+
+    return;
+}
+
+
+/*
+    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)
+{
+    char    ch;
+    coord   old_hero;
+    char    hch;
+
+    firstmove = FALSE;
+
+    if (player.t_no_move)
+    {
+        player.t_no_move--;
+        msg("You are still stuck in the bear trap.");
+        return;
+    }
+
+    /* Do a confused move (maybe) */
+
+    if ((rnd(100) < 80 && on(player, ISHUH)) ||
+        (is_wearing(R_DELUSION) && rnd(100) < 25) ||
+        on(player, STUMBLER) && rnd(40) == 0)
+        player.t_nxtpos = rndmove(&player);
+    else
+    {
+        player.t_nxtpos.y = hero.y + dy;
+        player.t_nxtpos.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 (player.t_nxtpos.x < 0 || player.t_nxtpos.x > COLS - 1 || player.t_nxtpos.y < 1 || player.t_nxtpos.y >= LINES - 2
+        || !diag_ok(&hero, &player.t_nxtpos, &player))
+    {
+        after = fighting = running = FALSE;
+        return;
+    }
+
+    if (running && ce(hero, player.t_nxtpos))
+        after = running = FALSE;
+
+    ch = winat(player.t_nxtpos.y, player.t_nxtpos.x);
+
+	if (isalpha(ch))
+	    debug("Moving onto monster %c",ch);
+    
+	/* Take care of hero trying to move close to something frightening */
+    
+	if (on(player, ISFLEE))
+    {
+        if (rnd(10) < 1)
+        {
+            turn_off(player, ISFLEE);
+            msg("You regain your composure.");
+        }
+        else if (DISTANCE(player.t_nxtpos, player.t_chasee->t_pos) <
+                 DISTANCE(hero,player.t_chasee->t_pos))
+            return;
+    }
+
+    /* Take care of hero being held */
+
+    if (on(player, ISHELD) && !isalpha(ch))
+    {
+        if (rnd(pstats.s_str) > 14)
+        {
+            msg("You break free of the hold.");
+
+            if (--hold_count == 0)
+                turn_off(player, ISHELD);
+        }
+        else
+        {
+            msg("You are being held.");
+            return;
+        }
+    }
+ 
+    /* Might lose disguise */
+
+    if (on(player, ISDISGUISE) && rnd(11 * pstats.s_dext) == 0)
+    {
+        extinguish_fuse(FUSE_UNDISGUISE);
+        undisguise(NULL);
+    }
+
+    /* assume he's not in a wall */
+
+    if (!isalpha(ch))
+        turn_off(player, ISINWALL);
+
+    hch = CCHAR( mvinch(hero.y, hero.x) );   /* Where hero was */
+    old_hero = hero;    /* Save hero's old position */
+
+    switch (ch)
+    {
+        case ' ':
+        case '|':
+        case '-':
+        case SECRETDOOR:
+            if (off(player, CANINWALL))
+            {
+                after = running = FALSE;
+                return;
+            }
+            else if (running)
+            {
+                after = running = FALSE;
+                return;
+            }
+            turn_on(player, ISINWALL);
+            break;
+
+        case TRAPDOOR:
+        case TELTRAP:
+        case BEARTRAP:
+        case SLEEPTRAP:
+        case ARROWTRAP:
+        case DARTTRAP:
+        case POOL:
+        case MAZETRAP:
+        case FIRETRAP:
+        case POISONTRAP:
+        case LAIR:
+        case RUSTTRAP:
+            ch = be_trapped(&player, player.t_nxtpos);
+
+            if (!is_wearing(R_LEVITATION) && off(player, CANFLY) &&
+                (old_hero.x != hero.x || old_hero.y != hero.y
+                 || pool_teleport))
+            {
+                pool_teleport = FALSE;
+                return;
+            }
+
+            break;
+
+        case GOLD:
+        case POTION:
+        case SCROLL:
+        case FOOD:
+        case WEAPON:
+        case ARMOR:
+        case RING:
+        case ARTIFACT:
+        case STICK:
+            running = FALSE;
+            take = ch;
+            break;
+
+        default:
+            break;
+    }
+
+    if (ch == FIRETRAP)
+        light(&hero);
+
+    hero = player.t_nxtpos;      /* Move the hero */
+	
+	/* adjust lighting */
+
+    if (roomin(hero) == NULL && (hch == '-' || hch == '|' ||
+        hch == DOOR || hch == SECRETDOOR))
+    {
+        /* Leaving a room -- darken it */
+        struct room *rp = roomin(old_hero);
+        int    is_lit = FALSE;
+
+        if (!(rp->r_flags & ISDARK))
+            is_lit = TRUE;
+
+        rp->r_flags |= ISDARK;  /* Fake darkness */
+        light(&old_hero);
+
+        if (is_lit)
+            rp->r_flags &= ~ISDARK; /* Restore light state */
+    }
+    else if (ch == DOOR || ch == SECRETDOOR || ch == '|' || ch == '-')
+    {
+        /* Entering a room */
+        running = FALSE;
+        if (hch != '|' && hch != '-')
+            light(&hero);   /* knows whether the hero can see things in */
+    }	
+	
+	/* handle other situations */
+	
+    if (ch == STAIRS)
+        running = FALSE;
+    else if (ch == POST)
+    {
+        running = FALSE;
+        new_level(POSTLEV,0);
+        return;
+    }
+    else if (isalpha(ch))
+    {
+        struct linked_list  *mp;
+        struct thing    *tp;
+        char t;
+
+        running = FALSE;
+
+        mp = find_mons(hero.y, hero.x);
+
+        if (mp == NULL)
+            return;
+
+        tp = THINGPTR(mp);
+
+        if (good_monster(*tp))  /* Exchange places with your buddy */
+        {
+            mvwaddch(cw, old_hero.y, old_hero.x, ch);
+            mvwaddch(mw, old_hero.y, old_hero.x, ch);
+            mvwaddch(mw, hero.y, hero.x, ' ');
+            mvwaddch(cw, hero.y, hero.x, tp->t_oldch);
+
+            (*tp).t_pos.x = old_hero.x; /* Update monster position variables */
+            (*tp).t_pos.y = old_hero.y;
+            (*tp).t_oldpos.x = old_hero.x;
+            (*tp).t_oldpos.y = old_hero.y;
+
+            t = (*tp).t_oldch;
+            (*tp).t_oldch = player.t_oldch;
+            player.t_oldch = t;
+
+            turn_on(*tp, ISRUN);
+
+            mvwaddch(cw, hero.y, hero.x, PLAYER);
+			
+			/* make sure that the room shows OK */
+			
+			light(&hero);
+			
+            wrefresh(cw);
+            return;
+        }
+        else
+        {
+            hero = old_hero; /* Restore hero -- we'll fight instead of move */
+
+			/* make sure that the room shows OK */
+    		light(&hero);
+
+            fight(&player.t_nxtpos, cur_weapon, NOTHROWN);
+
+            return;
+        }
+    }
+    else
+        fighting = FALSE;
+
+    ch = winat(old_hero.y, old_hero.x);
+    mvwaddch(cw, old_hero.y, old_hero.x, ch);
+    mvwaddch(cw, hero.y, hero.x, PLAYER);
+}
+
+/*
+    light()
+        Called to illuminate a room. If it is dark, remove anything that might
+        move.
+*/
+
+void
+light(coord *cp)
+{
+    struct room *rp;
+    int j, k, x, y;
+    char    ch, rch;
+    struct linked_list  *item;
+    int jlow, jhigh, klow, khigh;   /* Boundaries of lit area */
+
+    if ((rp = roomin(*cp)) != NULL && !on(player, ISBLIND))
+    {
+
+        /* is he wearing ring of illumination and in same room? */
+
+        if ((is_wearing(R_LIGHT) || on(player, ISELECTRIC)) &&
+            cp == &hero)
+            rp->r_flags &= ~ISDARK;
+
+        /* If we are in a maze, don't look at the whole room (level) */
+
+        if (levtype == MAZELEV)
+        {
+            jlow = max(0, hero.y - 2 - rp->r_pos.y);
+            jhigh = min(rp->r_max.y, hero.y + 2 - rp->r_pos.y + 1);
+            klow = max(0, hero.x - 2 - rp->r_pos.x);
+            khigh = min(rp->r_max.x, hero.x + 2 - rp->r_pos.x + 1);
+        }
+        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++)
+            {
+                /* Is this in the given 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;
+
+                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 = '|';
+                }
+
+                /*
+                 * For monsters, if they were previously not
+                 * seen and now can be seen, or vice-versa,
+                 * make sure that will happen.
+                 */
+
+                if (isalpha(ch))
+                {
+                    struct thing    *tp;
+
+                    item = wake_monster(y, x);
+
+                    if (item == NULL)
+                        continue;
+
+                    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 = CCHAR( mvinch(y, x) );
+
+                    /* Previously seen -- now can't see it */
+
+                    else if (off(player, ISBLIND) && tp->t_oldch != ' ' &&
+                         !cansee(tp->t_pos.y, tp->t_pos.x))
+                        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 or
+                 * not in line-of-sight in a maze.
+                 */
+
+                if (((rp->r_flags & ISDARK) &&
+                    !(rp->r_flags & HASFIRE)) ||
+                    (levtype == MAZELEV &&
+                     !maze_view(y, x)))
+                {
+                    rch = CCHAR( mvwinch(cw, y, x) );
+
+                    switch (rch)
+                    {
+                        case DOOR:
+                        case STAIRS:
+                        case TRAPDOOR:
+                        case TELTRAP:
+                        case BEARTRAP:
+                        case SLEEPTRAP:
+                        case ARROWTRAP:
+                        case DARTTRAP:
+                        case POOL:
+                        case MAZETRAP:
+                        case FIRETRAP:
+                        case POISONTRAP:
+                        case LAIR:
+                        case RUSTTRAP:
+                        case POST:
+                        case '|':
+                        case '-':
+                        case ' ':
+                            ch = rch;
+                            break;
+
+                        case    FLOOR:
+                            ch = (on(player, ISBLIND) ? FLOOR : ' ');
+                            break;
+                        default:
+                            ch = ' ';
+                            break;
+                    }
+                }
+                mvwaddch(cw, y, x, ch);
+            }
+        }
+    }
+}
+
+/*
+    blue_light()
+        magically light up a room (or level or make it dark)
+*/
+
+int
+blue_light(int flags)
+{
+    struct room *rp;
+    int  blessed = (flags & ISBLESSED);
+    int  cursed = (flags & ISCURSED);
+    int  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) || (rp->r_flags & ISDARK))
+            nothing_message(flags);
+        else
+        {
+            if (!(rp->r_flags & HASFIRE))
+                msg("The room suddenly goes dark.");
+            else
+                nothing_message(flags);
+
+            rp->r_flags |= ISDARK;
+            ret_val = TRUE;
+        }
+    }
+    else
+    {
+        ret_val = TRUE;
+
+        if (rp && (rp->r_flags & ISDARK) && !(rp->r_flags & HASFIRE))
+        {
+            msg("The room is lit by a %s blue light.",
+                 blessed ? "bright" : "shimmering");
+        }
+        else if (winat(hero.y, hero.x) == PASSAGE)
+            msg("The corridor glows %sand then fades.", blessed ? "brightly " : "");
+        else
+        {
+            ret_val = FALSE;
+            nothing_message(flags);
+        }
+
+        if (blessed)
+        {
+            short   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);
+}
+
+/*