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